mirror of
https://github.com/arabianq/colorgram-rust.git
synced 2026-04-28 06:31:22 +00:00
add docs
This commit is contained in:
+64
@@ -4,6 +4,11 @@ use std::{
|
|||||||
fmt::{Display, Formatter, Result as fmtResult},
|
fmt::{Display, Formatter, Result as fmtResult},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents a color in the HSL (Hue, Saturation, Lightness) color space.
|
||||||
|
///
|
||||||
|
/// Note: In this implementation, values are stored as `u8` (0-255) rather than
|
||||||
|
/// the standard degrees (0-360) and percentages (0-100), following the
|
||||||
|
/// integer-based logic inherited from `colorgram.py`.
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct Hsl {
|
pub struct Hsl {
|
||||||
pub h: u8,
|
pub h: u8,
|
||||||
@@ -17,6 +22,7 @@ impl Display for Hsl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a color in the RGB (Red, Green, Blue) color space.
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct Rgb {
|
pub struct Rgb {
|
||||||
pub r: u8,
|
pub r: u8,
|
||||||
@@ -30,14 +36,24 @@ impl Display for Rgb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A structure representing an extracted color, its HSL equivalent,
|
||||||
|
/// and its prevalence in the image.
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
|
/// The average RGB color of the cluster.
|
||||||
pub rgb: Rgb,
|
pub rgb: Rgb,
|
||||||
|
/// The HSL representation (calculated using the bug-compatible `rgb_to_hsl`).
|
||||||
pub hsl: Hsl,
|
pub hsl: Hsl,
|
||||||
|
/// The proportion of this color in the image (range 0.0 to 1.0).
|
||||||
pub proportion: f32,
|
pub proportion: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
|
/// Creates a new `Color` instance and automatically calculates its HSL value.
|
||||||
|
///
|
||||||
|
/// ### Arguments:
|
||||||
|
/// * `rgb` - The base RGB color.
|
||||||
|
/// * `proportion` - The weight of this color relative to others.
|
||||||
pub fn new(rgb: Rgb, proportion: f32) -> Color {
|
pub fn new(rgb: Rgb, proportion: f32) -> Color {
|
||||||
let hsl = rgb_to_hsl(&rgb);
|
let hsl = rgb_to_hsl(&rgb);
|
||||||
Color {
|
Color {
|
||||||
@@ -48,6 +64,25 @@ impl Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts RGB color space to HSL.
|
||||||
|
///
|
||||||
|
/// ### ⚠️ Bug-compatibility Warning:
|
||||||
|
/// This function **does not** produce a mathematically correct HSL value. It contains
|
||||||
|
/// specific calculation errors inherited from the original `colorgram.py` library.
|
||||||
|
/// These deviations are preserved intentionally to ensure that the color extraction
|
||||||
|
/// results remain identical to the Python implementation.
|
||||||
|
///
|
||||||
|
/// ### Implementation Details:
|
||||||
|
/// * **Luminance (L)**: Calculated as the average of the most and least dominant components.
|
||||||
|
/// * **Saturation (S)**: Scaled to 0-255 range using integer division that may lose precision.
|
||||||
|
/// * **Hue (H)**: Calculated using a 0-255 scale (instead of 0-360°) with custom offsets
|
||||||
|
/// (1530, 510, 1020) and integer math.
|
||||||
|
///
|
||||||
|
/// ### Arguments:
|
||||||
|
/// * `rgb` - A reference to the input `Rgb` struct.
|
||||||
|
///
|
||||||
|
/// ### Returns:
|
||||||
|
/// * `Hsl` - The "colorgram-style" HSL representation.
|
||||||
fn rgb_to_hsl(rgb: &Rgb) -> Hsl {
|
fn rgb_to_hsl(rgb: &Rgb) -> Hsl {
|
||||||
let r = rgb.r as i32;
|
let r = rgb.r as i32;
|
||||||
let g = rgb.g as i32;
|
let g = rgb.g as i32;
|
||||||
@@ -80,6 +115,35 @@ fn rgb_to_hsl(rgb: &Rgb) -> Hsl {
|
|||||||
Hsl { h, s, l: l as u8 }
|
Hsl { h, s, l: l as u8 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts a palette of dominant colors from an image buffer.
|
||||||
|
///
|
||||||
|
/// ### Process:
|
||||||
|
/// 1. **Decoding**: Loads the image from the provided byte buffer and converts it to RGB8.
|
||||||
|
/// 2. **Quantization**: Pixels are grouped into "buckets" based on a simplified 6-bit key
|
||||||
|
/// derived from Luminance (Y), Hue (H), and Lightness (L).
|
||||||
|
/// 3. **Aggregation**: Sums the R, G, and B components and counts pixels in each bucket.
|
||||||
|
/// 4. **Averaging**: Calculates the mean color for each non-empty bucket.
|
||||||
|
/// 5. **Selection**: Returns the top `number_of_color` most frequent colors.
|
||||||
|
///
|
||||||
|
/// ### Arguments:
|
||||||
|
/// * `buffer` - A byte slice containing encoded image data (e.g., JPEG, PNG).
|
||||||
|
/// * `number_of_color` - The maximum number of dominant colors to return.
|
||||||
|
///
|
||||||
|
/// ### Example:
|
||||||
|
/// ```rust
|
||||||
|
/// use colorgram::{extract, Color};
|
||||||
|
/// use std::fs;
|
||||||
|
///
|
||||||
|
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// let buf = fs::read("image.jpg")?;
|
||||||
|
/// let colors = extract(&buf, 5)?;
|
||||||
|
///
|
||||||
|
/// for color in colors {
|
||||||
|
/// println!("Color: {}, Weight: {:.2}%", color.rgb, color.proportion * 100.0);
|
||||||
|
/// }
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn extract(buffer: &[u8], number_of_color: usize) -> Result<Vec<Color>, Box<dyn Error>> {
|
pub fn extract(buffer: &[u8], number_of_color: usize) -> Result<Vec<Color>, Box<dyn Error>> {
|
||||||
let img = image::load_from_memory(buffer)?;
|
let img = image::load_from_memory(buffer)?;
|
||||||
let img = img.to_rgb8();
|
let img = img.to_rgb8();
|
||||||
|
|||||||
Reference in New Issue
Block a user