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