diff --git a/examples/simplecli.rs b/examples/simplecli.rs index 866f96f..e2a87c5 100644 --- a/examples/simplecli.rs +++ b/examples/simplecli.rs @@ -162,7 +162,7 @@ fn main() { .seed(seed), ) } else { - QuantizeMethod::Wu + QuantizeMethod::wu() }; let colorspace = colorspace.into(); diff --git a/src/api/colorspace.rs b/src/api/colorspace.rs index 64706a5..1c73572 100644 --- a/src/api/colorspace.rs +++ b/src/api/colorspace.rs @@ -5,11 +5,15 @@ use crate::{ QuantizeMethod, }; +#[cfg(all(feature = "kmeans", feature = "colorspaces"))] +use crate::kmeans::Centroids; #[cfg(feature = "kmeans")] -use crate::{kmeans::Centroids, KmeansOptions}; +use crate::KmeansOptions; #[cfg(feature = "colorspaces")] use crate::{wu::FloatBinner, ColorSlice}; +use std::marker::PhantomData; + #[cfg(feature = "colorspaces")] use ::palette::{IntoColor, LinSrgb, Srgb}; #[cfg(all(feature = "threads", feature = "colorspaces"))] @@ -149,18 +153,18 @@ where #[cfg(feature = "colorspaces")] impl QuantizeMethod> { /// Convert the colorspace + #[allow(unused_variables)] pub(crate) fn convert_color_space_from_srgb( self, convert_to: impl Fn(Srgb) -> Color, ) -> QuantizeMethod { match self { - QuantizeMethod::Wu => QuantizeMethod::Wu, + QuantizeMethod::Wu(_) => QuantizeMethod::Wu(PhantomData), #[cfg(feature = "kmeans")] QuantizeMethod::Kmeans(KmeansOptions { sampling_factor, initial_centroids, seed, - #[cfg(feature = "threads")] batch_size, }) => QuantizeMethod::Kmeans(KmeansOptions { initial_centroids: initial_centroids.map(|c| { @@ -168,9 +172,23 @@ impl QuantizeMethod> { }), sampling_factor, seed, - #[cfg(feature = "threads")] batch_size, }), } } } + +impl QuantizeMethod { + /// Creates a new [`QuantizeMethod::Wu`]. + #[must_use] + pub const fn wu() -> Self { + Self::Wu(PhantomData) + } + + /// Creates a new [`QuantizeMethod::Kmeans`] with the default [`KmeansOptions`]. + #[must_use] + #[cfg(feature = "kmeans")] + pub const fn kmeans() -> Self { + Self::Kmeans(KmeansOptions::new()) + } +} diff --git a/src/api/image_pipeline.rs b/src/api/image_pipeline.rs index 0475aef..e50bbb6 100644 --- a/src/api/image_pipeline.rs +++ b/src/api/image_pipeline.rs @@ -4,39 +4,38 @@ use super::num_samples; use crate::{ - dither::FloydSteinberg, wu, ColorComponents, ColorCounts, ColorCountsRemap, ColorSlice, - ColorSpace, IndexedColorCounts, PalettePipeline, PaletteSize, QuantizeMethod, + dither::FloydSteinberg, + wu::{self, Binner3}, + ColorComponents, ColorCounts, ColorCountsRemap, ColorSlice, ColorSpace, PalettePipeline, + PaletteSize, QuantizeMethod, SumPromotion, ZeroedIsZero, }; #[cfg(all(feature = "colorspaces", feature = "threads"))] use crate::colorspace::convert_color_slice_par; +#[cfg(feature = "colorspaces")] +use crate::colorspace::{convert_color_slice, from_srgb, to_srgb}; #[cfg(feature = "image")] use crate::AboveMaxLen; #[cfg(feature = "threads")] use crate::ColorCountsParallelRemap; -#[cfg(feature = "colorspaces")] -use crate::{ - colorspace::{convert_color_slice, from_srgb, to_srgb}, - wu::Binner3, - SumPromotion, ZeroedIsZero, -}; +#[cfg(any(feature = "colorspaces", feature = "kmeans"))] +use crate::IndexedColorCounts; #[cfg(feature = "kmeans")] use crate::{ kmeans::{self, Centroids}, KmeansOptions, }; +use num_traits::AsPrimitive; use palette::Srgb; #[cfg(feature = "image")] use image::RgbImage; -#[cfg(feature = "colorspaces")] -use num_traits::AsPrimitive; #[cfg(feature = "image")] use palette::cast::IntoComponents; #[cfg(feature = "colorspaces")] use palette::{Lab, Oklab}; -#[cfg(feature = "threads")] +#[cfg(all(feature = "threads", feature = "image"))] use rayon::prelude::*; /// A builder struct to specify options to create a quantized image or an indexed palette from an image. @@ -125,6 +124,7 @@ pub struct ImagePipeline<'a> { /// The error diffusion factor to use when dithering. pub(crate) dither_error_diffusion: f32, /// Whether or not to deduplicate the input pixels/colors. + #[cfg(any(feature = "kmeans", feature = "colorspaces"))] pub(crate) dedup_pixels: bool, } @@ -137,9 +137,10 @@ impl<'a> ImagePipeline<'a> { dimensions: (width, height), k: PaletteSize::default(), colorspace: ColorSpace::Srgb, - quantize_method: QuantizeMethod::Wu, + quantize_method: QuantizeMethod::wu(), dither: true, dither_error_diffusion: FloydSteinberg::DEFAULT_ERROR_DIFFUSION, + #[cfg(any(feature = "kmeans", feature = "colorspaces"))] dedup_pixels: true, } } @@ -274,6 +275,7 @@ impl<'a> ImagePipeline<'a> { colors, k, quantize_method, + #[cfg(feature = "kmeans")] dedup_pixels, dimensions, .. @@ -414,6 +416,7 @@ impl<'a> ImagePipeline<'a> { colors, k, quantize_method, + #[cfg(feature = "kmeans")] dedup_pixels, dimensions, .. @@ -539,6 +542,7 @@ impl<'a> ImagePipeline<'a> { } /// Computes a color palette and the indices into it. +#[allow(clippy::needless_pass_by_value)] fn indexed_palette( color_counts: &impl ColorCountsRemap, width: u32, @@ -556,7 +560,7 @@ where f32: AsPrimitive, { let (palette, mut indices) = match method { - QuantizeMethod::Wu => { + QuantizeMethod::Wu(_) => { let res = wu::indexed_palette(color_counts, k, binner); (res.palette, res.indices) } @@ -595,6 +599,7 @@ where /// Computes a color palette and the indices into it in parallel. #[cfg(feature = "threads")] +#[allow(clippy::needless_pass_by_value)] fn indexed_palette_par( color_counts: &(impl ColorCountsParallelRemap + Send + Sync), width: u32, @@ -612,7 +617,7 @@ where f32: AsPrimitive, { let (palette, mut indices) = match method { - QuantizeMethod::Wu => { + QuantizeMethod::Wu(_) => { let res = wu::indexed_palette_par(color_counts, k, binner); (res.palette, res.indices) } diff --git a/src/api/mod.rs b/src/api/mod.rs index 83a22cf..71c77ba 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -8,10 +8,10 @@ pub use colorspace::ColorSpace; pub use image_pipeline::ImagePipeline; pub use palette_pipeline::PalettePipeline; -use crate::{ColorComponents, ColorCounts}; - #[cfg(feature = "kmeans")] -use crate::kmeans::Centroids; +use crate::{kmeans::Centroids, ColorComponents, ColorCounts}; + +use std::marker::PhantomData; /// A builder struct to specify the parameters for k-means. /// @@ -33,10 +33,11 @@ pub struct KmeansOptions { /// The seed value for the random number generator. seed: u64, /// The batch size for minibatch k-means. - #[cfg(feature = "threads")] + #[allow(unused)] batch_size: u32, } +#[cfg(feature = "kmeans")] impl Default for KmeansOptions { fn default() -> Self { Self::new() @@ -47,12 +48,11 @@ impl Default for KmeansOptions { impl KmeansOptions { /// Creates a new [`KmeansOptions`] with default values. #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { sampling_factor: 0.5, initial_centroids: None, seed: 0, - #[cfg(feature = "threads")] batch_size: 4096, } } @@ -129,7 +129,7 @@ pub enum QuantizeMethod { /// This method is quick and gives good or at least decent results. /// /// See the [`wu`](crate::wu) module for more details. - Wu, + Wu(PhantomData), /// Color quantization using k-means clustering. /// /// This method is slower than Wu's color quantizer but gives more accurate results. diff --git a/src/api/palette_pipeline.rs b/src/api/palette_pipeline.rs index e2dfdbf..f56c265 100644 --- a/src/api/palette_pipeline.rs +++ b/src/api/palette_pipeline.rs @@ -4,33 +4,31 @@ use super::num_samples; use crate::{ - wu, ColorComponents, ColorCounts, ColorSlice, ColorSpace, ImagePipeline, PaletteSize, - QuantizeMethod, UniqueColorCounts, + wu::{self, Binner3}, + ColorComponents, ColorCounts, ColorSlice, ColorSpace, ImagePipeline, PaletteSize, + QuantizeMethod, SumPromotion, ZeroedIsZero, }; #[cfg(all(feature = "colorspaces", feature = "threads"))] use crate::colorspace::convert_color_slice_par; +#[cfg(feature = "colorspaces")] +use crate::colorspace::{convert_color_slice, from_srgb, to_srgb}; #[cfg(feature = "image")] use crate::AboveMaxLen; -#[cfg(feature = "colorspaces")] -use crate::{ - colorspace::{convert_color_slice, from_srgb, to_srgb}, - wu::Binner3, - SumPromotion, ZeroedIsZero, -}; +#[cfg(any(feature = "colorspaces", feature = "kmeans"))] +use crate::UniqueColorCounts; #[cfg(feature = "kmeans")] use crate::{ kmeans::{self, Centroids}, KmeansOptions, }; +use num_traits::AsPrimitive; use palette::Srgb; #[cfg(feature = "image")] use image::RgbImage; #[cfg(feature = "colorspaces")] -use num_traits::AsPrimitive; -#[cfg(feature = "colorspaces")] use palette::{Lab, Oklab}; /// A builder struct to specify options to create a color palette for an image or slice of colors. @@ -132,6 +130,7 @@ pub struct PalettePipeline<'a> { /// The color quantization method to use. pub(crate) quantize_method: QuantizeMethod>, /// Whether or not to deduplicate the input pixels/colors. + #[cfg(any(feature = "kmeans", feature = "colorspaces"))] pub(crate) dedup_pixels: bool, } @@ -143,7 +142,8 @@ impl<'a> PalettePipeline<'a> { colors, k: PaletteSize::default(), colorspace: ColorSpace::Srgb, - quantize_method: QuantizeMethod::Wu, + quantize_method: QuantizeMethod::wu(), + #[cfg(any(feature = "kmeans", feature = "colorspaces"))] dedup_pixels: true, } } @@ -214,6 +214,7 @@ impl<'a> From> for PalettePipeline<'a> { k, colorspace, quantize_method, + #[cfg(any(feature = "kmeans", feature = "colorspaces"))] dedup_pixels, .. } = value; @@ -223,6 +224,7 @@ impl<'a> From> for PalettePipeline<'a> { k, colorspace, quantize_method, + #[cfg(any(feature = "kmeans", feature = "colorspaces"))] dedup_pixels, } } @@ -235,7 +237,12 @@ impl<'a> PalettePipeline<'a> { match self.colorspace { ColorSpace::Srgb => { let Self { - colors, k, quantize_method, dedup_pixels, .. + colors, + k, + quantize_method, + #[cfg(feature = "kmeans")] + dedup_pixels, + .. } = self; match quantize_method { @@ -315,7 +322,12 @@ impl<'a> PalettePipeline<'a> { match self.colorspace { ColorSpace::Srgb => { let Self { - colors, k, quantize_method, dedup_pixels, .. + colors, + k, + quantize_method, + #[cfg(feature = "kmeans")] + dedup_pixels, + .. } = self; match quantize_method { @@ -390,6 +402,7 @@ impl<'a> PalettePipeline<'a> { } /// Computes a color palette. +#[allow(clippy::needless_pass_by_value)] fn palette( color_counts: &impl ColorCounts, k: PaletteSize, @@ -404,7 +417,7 @@ where f32: AsPrimitive, { match method { - QuantizeMethod::Wu => wu::palette(color_counts, k, binner).palette, + QuantizeMethod::Wu(_) => wu::palette(color_counts, k, binner).palette, #[cfg(feature = "kmeans")] QuantizeMethod::Kmeans(KmeansOptions { sampling_factor, initial_centroids, seed, .. @@ -422,6 +435,7 @@ where /// Computes a color palette in parallel. #[cfg(feature = "threads")] +#[allow(clippy::needless_pass_by_value)] fn palette_par( color_counts: &(impl ColorCounts + Send + Sync), k: PaletteSize, @@ -436,7 +450,7 @@ where f32: AsPrimitive, { match method { - QuantizeMethod::Wu => wu::palette_par(color_counts, k, binner).palette, + QuantizeMethod::Wu(_) => wu::palette_par(color_counts, k, binner).palette, #[cfg(feature = "kmeans")] QuantizeMethod::Kmeans(KmeansOptions { sampling_factor, diff --git a/src/color_counts.rs b/src/color_counts.rs index d34a304..ccd255b 100644 --- a/src/color_counts.rs +++ b/src/color_counts.rs @@ -12,7 +12,7 @@ use palette::cast::{self, AsArrays}; #[cfg(feature = "image")] use image::RgbImage; -#[cfg(any(feature = "image", feature = "colorspaces"))] +#[cfg(feature = "image")] use palette::Srgb; #[cfg(feature = "threads")] use rayon::prelude::*; diff --git a/src/dither.rs b/src/dither.rs index cdff952..063a078 100644 --- a/src/dither.rs +++ b/src/dither.rs @@ -18,8 +18,8 @@ impl FloydSteinberg { /// Creates a new [`FloydSteinberg`] with the default error diffusion factor. #[must_use] - pub fn new() -> Self { - Self::default() + pub const fn new() -> Self { + Self(Self::DEFAULT_ERROR_DIFFUSION) } /// Creates a new [`FloydSteinberg`] with the given error diffusion factor. @@ -46,7 +46,7 @@ impl FloydSteinberg { impl Default for FloydSteinberg { fn default() -> Self { - Self(Self::DEFAULT_ERROR_DIFFUSION) + Self::new() } } diff --git a/src/kmeans.rs b/src/kmeans.rs index 78349dc..d450209 100644 --- a/src/kmeans.rs +++ b/src/kmeans.rs @@ -69,6 +69,7 @@ impl Centroids { /// Creates a [`Centroids`] without ensuring that its length /// is less than or equal to [`MAX_COLORS`]. + #[allow(unused)] pub(crate) fn new_unchecked(centroids: Vec) -> Self { Self(centroids) }