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