Skip to main content

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 crate::bit_depth::BitDepth;
10use crate::colorspace::ColorSpace;
11
12/// The type and strength of applied compression.
13///
14/// This is a simple, high-level interface that will automatically choose
15/// the appropriate DEFLATE compression mode and PNG filter.
16///
17/// If you need more control over the encoding parameters,
18/// you can set the [DeflateCompression] and [Filter] manually.
19#[derive(Debug, Clone, Copy, Default)]
20pub enum PngCompression {
21    /// No compression whatsoever. Fastest, but results in large files.
22    NoCompression,
23    /// Extremely fast but light compression.
24    ///
25    /// Note: When used in streaming mode, this compression level can actually result in files
26    /// *larger* than would be produced by `NoCompression` on incompressible data because
27    /// it doesn't do any buffering of the output stream to detect whether the data is being compressed or not.
28    Fastest,
29    /// Extremely fast compression with a decent compression ratio.
30    ///
31    /// Significantly outperforms libpng and other popular encoders by using a [specialized DEFLATE
32    /// implementation tuned for PNG](https://crates.io/crates/fdeflate), while still providing
33    /// better compression ratio than the fastest modes of other encoders.
34    ///
35    /// Like `Compression::Fast` this can currently produce files larger than `NoCompression` in
36    /// streaming mode when given incompressible data. This may change in the future.
37    Fast,
38    /// Balances encoding speed and compression ratio
39    #[default]
40    Balanced,
41    /// Spend much more time to produce a slightly smaller file than with `Balanced`.
42    High
43}
44/// Encoder options that are flags
45#[derive(Copy, Debug, Clone, Default)]
46struct EncoderFlags {
47    /// Whether JPEG images should be encoded as progressive images
48    jpeg_encode_progressive: bool,
49    /// Whether JPEG images should use optimized huffman tables
50    jpeg_optimize_huffman:   bool,
51    /// Whether to not preserve metadata across image transformations
52    image_strip_metadata:    bool,
53    /// png compression
54    png_compression_level:   PngCompression
55}
56
57/// Options shared by some of the encoders in
58/// the `zune-` family of image crates
59#[derive(Debug, Copy, Clone)]
60pub struct EncoderOptions {
61    width:       usize,
62    height:      usize,
63    colorspace:  ColorSpace,
64    quality:     u8,
65    depth:       BitDepth,
66    num_threads: u8,
67    effort:      u8,
68    flags:       EncoderFlags
69}
70
71impl Default for EncoderOptions {
72    fn default() -> Self {
73        Self {
74            width:       0,
75            height:      0,
76            colorspace:  ColorSpace::RGB,
77            quality:     80,
78            depth:       BitDepth::Eight,
79            num_threads: 4,
80            effort:      4,
81            flags:       EncoderFlags::default()
82        }
83    }
84}
85
86impl EncoderOptions {
87    ///  Create  new encode options
88    ///
89    /// # Arguments
90    ///  
91    /// * `width`: Image width
92    /// * `height`: Image height
93    /// * `colorspace`:  Image colorspaces
94    /// * `depth`: Image depth
95    ///
96    /// returns: EncoderOptions
97    ///
98    pub fn new(
99        width: usize, height: usize, colorspace: ColorSpace, depth: BitDepth
100    ) -> EncoderOptions {
101        EncoderOptions {
102            width,
103            height,
104            colorspace,
105            depth,
106            ..Default::default()
107        }
108    }
109    /// Get the width for which the image will be encoded in
110    pub const fn width(&self) -> usize {
111        self.width
112    }
113
114    /// Get height for which the image will be encoded in
115    ///
116    /// returns: usize
117    ///
118    /// # Panics
119    /// If height is zero
120    pub fn height(&self) -> usize {
121        assert_ne!(self.height, 0);
122        self.height
123    }
124    /// Get the depth for which the image will be encoded in
125    pub const fn depth(&self) -> BitDepth {
126        self.depth
127    }
128    /// Get the quality for which the image will be encoded with
129    ///
130    ///  # Lossy
131    /// - Higher quality means some images take longer to write and
132    ///   have large file sizes but they look good (closer to lossless)
133    ///
134    /// - Lower quality means small images and low quality.
135    ///
136    /// # Lossless
137    /// - High quality indicates more time is spent in making the file
138    ///   smaller
139    ///
140    /// - Low quality indicates less time is spent in making the file bigger
141    pub const fn quality(&self) -> u8 {
142        self.quality
143    }
144    /// Get the colorspace for which the image will be encoded in
145    pub const fn colorspace(&self) -> ColorSpace {
146        self.colorspace
147    }
148    pub const fn effort(&self) -> u8 {
149        self.effort
150    }
151
152    /// Set width for the image to be encoded
153    pub fn set_width(mut self, width: usize) -> Self {
154        self.width = width;
155        self
156    }
157
158    /// Set height for the image to be encoded
159    pub fn set_height(mut self, height: usize) -> Self {
160        self.height = height;
161        self
162    }
163    /// Set depth for the image to be encoded
164    pub fn set_depth(mut self, depth: BitDepth) -> Self {
165        self.depth = depth;
166        self
167    }
168    /// Set quality of the image to be encoded
169    ///
170    /// Quality is clamped from 0..100
171    ///
172    /// Quality means different options depending on the encoder, see
173    /// [get_quality](Self::quality)
174    pub fn set_quality(mut self, quality: u8) -> Self {
175        self.quality = quality.clamp(0, 100);
176        self
177    }
178    /// Set colorspace for the image to be encoded
179    pub fn set_colorspace(mut self, colorspace: ColorSpace) -> Self {
180        self.colorspace = colorspace;
181        self
182    }
183    /// Set the number of threads allowed for multithreaded encoding
184    /// where supported
185    ///
186    /// Zero means use a single thread
187    pub fn set_num_threads(mut self, threads: u8) -> Self {
188        self.num_threads = threads;
189
190        self
191    }
192    pub fn set_effort(mut self, effort: u8) -> Self {
193        self.effort = effort;
194        self
195    }
196
197    /// Return number of threads configured for multithreading
198    /// where possible
199    ///
200    /// This is used for multi-threaded encoders,
201    /// currently only jpeg-xl
202    pub const fn num_threads(&self) -> u8 {
203        self.num_threads
204    }
205
206    /// Set whether the encoder should remove metadata from the image
207    ///
208    /// When set to `true`, supported encoders will strip away metadata
209    /// from the resulting image. If set to false, where supported, encoders
210    /// will not remove metadata from images
211    pub fn set_strip_metadata(mut self, yes: bool) -> Self {
212        self.flags.image_strip_metadata = yes;
213        self
214    }
215    /// Whether or not the encoder should remove metadata from the image
216    ///
217    /// The default value is false, and encoders that respect this try to preserve as much
218    /// data as possible from one image to another
219    pub const fn strip_metadata(&self) -> bool {
220        self.flags.image_strip_metadata
221    }
222}
223
224/// JPEG options
225impl EncoderOptions {
226    /// Whether the jpeg encoder should encode the image in progressive mode
227    ///
228    /// Default is `false`.
229    ///
230    /// This may be used to create slightly smaller images at the cost of more processing
231    /// time
232    pub const fn jpeg_encode_progressive(&self) -> bool {
233        self.flags.jpeg_encode_progressive
234    }
235
236    /// Whether the jpeg encoder should optimize huffman tables to create smaller files
237    /// at the cost of processing time
238    ///
239    /// Default is `false`.
240    pub const fn jpeg_optimized_huffman_tables(&self) -> bool {
241        self.flags.jpeg_optimize_huffman
242    }
243
244    /// Set whether the jpeg encoder should encode the imagei in progressive mode
245    ///
246    /// Default is `false`
247    pub fn set_jpeg_encode_progressive(mut self, yes: bool) -> Self {
248        self.flags.jpeg_optimize_huffman = yes;
249        self
250    }
251}
252
253impl EncoderOptions {
254    /// Get png compression level
255    pub const fn png_compression_level(&self) -> PngCompression {
256        self.flags.png_compression_level
257    }
258    /// Set png compression level
259    pub fn set_png_compression_level(mut self, value: PngCompression) -> Self {
260        self.flags.png_compression_level = value;
261        self
262    }
263}