From 5aea448bd2a7f6157cf33a6a2c044d043bbcd3ec Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Sat, 2 May 2020 13:46:25 -0400
Subject: color/source: Implement color sources

---
 src/color.rs        |  2 ++
 src/color/source.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)
 create mode 100644 src/color/source.rs

(limited to 'src')

diff --git a/src/color.rs b/src/color.rs
index a062795..e0a3399 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -1,5 +1,7 @@
 //! Colors and color spaces.
 
+pub mod source;
+
 use crate::metric::kd::{Cartesian, CartesianMetric};
 use crate::metric::{Metric, SquaredDistance};
 
diff --git a/src/color/source.rs b/src/color/source.rs
new file mode 100644
index 0000000..bd752d9
--- /dev/null
+++ b/src/color/source.rs
@@ -0,0 +1,76 @@
+//! Sources of colors.
+
+use super::Rgb8;
+
+use image::RgbImage;
+
+/// A source of colors in multidimensional space.
+pub trait ColorSource {
+    /// Get the size of each dimension in this space.
+    fn dimensions(&self) -> &[usize];
+
+    /// Get the color at some particular coordinates.
+    fn get_color(&self, coords: &[usize]) -> Rgb8;
+}
+
+/// The entire RGB space.
+#[derive(Debug)]
+pub struct AllColors {
+    dims: [usize; 3],
+    shifts: [usize; 3],
+}
+
+impl AllColors {
+    /// Create an AllColors source with the given bit depth.
+    pub fn new(bits: usize) -> Self {
+        // Allocate bits from most to least perceptually important
+        let gbits = (bits + 2) / 3;
+        let rbits = (bits + 1) / 3;
+        let bbits = bits / 3;
+
+        Self {
+            dims: [1 << rbits, 1 << gbits, 1 << bbits],
+            shifts: [8 - rbits, 8 - gbits, 8 - bbits],
+        }
+    }
+}
+
+impl ColorSource for AllColors {
+    fn dimensions(&self) -> &[usize] {
+        &self.dims
+    }
+
+    fn get_color(&self, coords: &[usize]) -> Rgb8 {
+        Rgb8::from([
+            (coords[0] << self.shifts[0]) as u8,
+            (coords[1] << self.shifts[1]) as u8,
+            (coords[2] << self.shifts[2]) as u8,
+        ])
+    }
+}
+
+/// Colors extracted from an image.
+#[derive(Debug)]
+pub struct ImageColors {
+    dims: [usize; 2],
+    image: RgbImage,
+}
+
+impl From<RgbImage> for ImageColors {
+    fn from(image: RgbImage) -> Self {
+        Self {
+            dims: [image.width() as usize, image.height() as usize],
+            image: image,
+        }
+    }
+}
+
+impl ColorSource for ImageColors {
+    fn dimensions(&self) -> &[usize] {
+        &self.dims
+    }
+
+    fn get_color(&self, coords: &[usize]) -> Rgb8 {
+        *self.image.get_pixel(coords[0] as u32, coords[1] as u32)
+    }
+}
-- 
cgit v1.2.3