Browse Source

Cleanups and a bugfix.

Kestrel 5 months ago
parent
commit
a190354f94
6 changed files with 115 additions and 103 deletions
  1. 5 1
      src/colour.rs
  2. 0 68
      src/formats.rs
  3. 45 2
      src/lib.rs
  4. 63 27
      src/ops.rs
  5. 1 4
      src/ops/helpers.rs
  6. 1 1
      src/ops/impls.rs

+ 5 - 1
src/colour.rs

@@ -57,10 +57,14 @@ impl Colour {
 impl Colour {
     pub const BLACK: Colour = Self::rgba(0, 0, 0, 255);
     pub const WHITE: Colour = Self::rgba(255, 255, 255, 255);
+    pub const GREY: Colour = Self::rgba(128, 128, 128, 255);
+    pub const TRANSPARENT_GREY: Colour = Self::rgba(128, 128, 128, 128);
     pub const RED: Colour = Self::rgba(255, 0, 0, 255);
+    pub const DARK_RED: Colour = Self::rgba(64, 0, 0, 255);
     pub const GREEN: Colour = Self::rgba(0, 255, 0, 255);
+    pub const DARK_GREEN: Colour = Self::rgba(0, 64, 0, 255);
     pub const BLUE: Colour = Self::rgba(0, 0, 255, 255);
-    pub const TRANSPARENT_GREY: Colour = Self::rgba(128, 128, 128, 128);
+    pub const DARK_BLUE: Colour = Self::rgba(0, 0, 64, 255);
 }
 
 /// Describes a blending mode between a backdrop and a source pixel.

+ 0 - 68
src/formats.rs

@@ -1,5 +1,3 @@
-use bitvec::{field::BitField, order::Lsb0, view::BitView};
-
 trait Sealed {}
 
 #[derive(Clone, PartialEq, Debug, Default)]
@@ -14,72 +12,6 @@ impl Mask {
     }
 }
 
-/*
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, enum_map::Enum)]
-pub enum DynamicPixelFormat {
-    A8,
-    Abgr32,
-    Bgr24,
-    Bgr32,
-    Rgb24,
-    Rgb32,
-    Rgba32,
-}
-
-macro_rules! masks_for {
-    ($n:ident) => {
-        ($n::RED_MASK, $n::GREEN_MASK, $n::BLUE_MASK, $n::ALPHA_MASK)
-    }
-}
-
-impl DynamicPixelFormat {
-    pub fn pixel_width(&self) -> usize {
-        match self {
-            Self::A8 => A8::PIXEL_WIDTH,
-            Self::Bgr24 => Bgr24::PIXEL_WIDTH,
-            Self::Bgr32 => Bgr32::PIXEL_WIDTH,
-            Self::Abgr32 => Abgr32::PIXEL_WIDTH,
-            Self::Rgb24 => Rgb24::PIXEL_WIDTH,
-            Self::Rgb32 => Rgb32::PIXEL_WIDTH,
-            Self::Rgba32 => Rgba32::PIXEL_WIDTH,
-        }
-    }
-
-    pub const fn masks(&self) -> (Mask, Mask, Mask, Mask) {
-        match self {
-            Self::A8 => masks_for!(A8),
-            Self::Abgr32 => masks_for!(Abgr32),
-            Self::Bgr24 => masks_for!(Bgr24),
-            Self::Bgr32 => masks_for!(Bgr32),
-            Self::Rgb24 => masks_for!(Rgb24),
-            Self::Rgb32 => masks_for!(Rgb32),
-            Self::Rgba32 => masks_for!(Rgba32),
-        }
-    }
-
-    pub fn red_mask(&self) -> Mask {
-        self.masks().0
-    }
-    pub fn green_mask(&self) -> Mask {
-        self.masks().1
-    }
-    pub fn blue_mask(&self) -> Mask {
-        self.masks().2
-    }
-    pub fn alpha_mask(&self) -> Mask {
-        self.masks().3
-    }
-
-    /*pub fn write_colour(&self, c: Colour, to: &mut [u8]) {
-        let bits = to.view_bits_mut::<Lsb0>();
-        bits[self.masks().0.0].store_be::<u8>(c.r);
-        bits[self.masks().1.0].store_be::<u8>(c.g);
-        bits[self.masks().2.0].store_be::<u8>(c.b);
-        bits[self.masks().3.0].store_be::<u8>(c.a);
-    }*/
-}
-*/
-
 #[allow(private_bounds)]
 pub trait PixelFormat: Sealed + Clone + Copy {
     const CHANNELS: usize;

+ 45 - 2
src/lib.rs

@@ -8,7 +8,7 @@ pub mod colour;
 pub mod formats;
 
 pub mod prelude {
-    pub use super::ops::{AlphaPaintable, Readable, RgbaPaintable, Writable};
+    pub use super::ops::{AlphaPaintable, Readable, RgbaPaintable, Paintable, Writable};
     pub use super::{BitmapAccess, BitmapMutAccess};
 }
 
@@ -133,7 +133,21 @@ pub struct BitmapRef<'l, Format: PixelFormat> {
 }
 
 impl<'l, Format: PixelFormat> BitmapRef<'l, Format> {
-    pub fn new(data: &'l [u8], width: usize, height: usize, stride: usize) -> Self {
+    /// Create a new bitmap reference using the default row stride.
+    pub fn new(data: &'l [u8], width: usize, height: usize) -> Self {
+        Self {
+            data: data::BorrowedBitmapData {
+                data,
+                width,
+                height,
+                stride: width * Format::PIXEL_WIDTH,
+            },
+            _ghost: Default::default(),
+        }
+    }
+
+    /// Create a new bitmap reference using a specific row stride.
+    pub fn new_with_stride(data: &'l [u8], width: usize, height: usize, stride: usize) -> Self {
         Self {
             data: data::BorrowedBitmapData {
                 data,
@@ -167,6 +181,35 @@ pub struct BitmapMut<'l, Format: PixelFormat> {
     _ghost: std::marker::PhantomData<Format>,
 }
 
+impl<'l, Format: PixelFormat> BitmapMut<'l, Format> {
+    /// Create a new mutable bitmap reference using the default row stride.
+    pub fn new(data: &'l mut [u8], width: usize, height: usize) -> Self {
+        Self {
+            data: data::MutableBitmapData {
+                data,
+                width,
+                height,
+                stride: width * Format::PIXEL_WIDTH,
+            },
+            _ghost: Default::default(),
+        }
+    }
+
+    /// Create a new mutable bitmap reference using a specific row stride.
+    pub fn new_with_stride(data: &'l mut [u8], width: usize, height: usize, stride: usize) -> Self {
+        Self {
+            data: data::MutableBitmapData {
+                data,
+                width,
+                height,
+                stride,
+            },
+            _ghost: Default::default(),
+        }
+    }
+    
+}
+
 impl<'l, Format: PixelFormat> BitmapAccess<Format> for BitmapMut<'l, Format> {
     fn data(&self) -> &[u8] {
         &self.data.data

+ 63 - 27
src/ops.rs

@@ -8,7 +8,7 @@ mod helpers;
 mod impls;
 
 pub trait Readable<PF: PixelFormat> {
-    type ReadResult;
+    type ReadResult: Clone;
     fn get_pixel(&self, x: usize, y: usize) -> Self::ReadResult;
 }
 
@@ -16,7 +16,67 @@ pub trait Writable<PF: PixelFormat>: Readable<PF> {
     fn set_pixel(&mut self, x: usize, y: usize, to: Self::ReadResult);
 }
 
+/// Generic image manipulation functionality
+pub trait Paintable<PF: PixelFormat>: BitmapMutAccess<PF> + Writable<PF> {
+    fn fill(&mut self, with: Self::ReadResult) {
+        for y in 0..self.height() {
+            for x in 0..self.width() {
+                self.set_pixel(x, y, with.clone());
+            }
+        }
+    }
+
+    /// Fill a region with a given value.
+    fn fill_region(&mut self, region: &math::PixelBox, with: Self::ReadResult) {
+        let image_box = math::PixelBox::from_size(self.size());
+        let Some(isect) = region.intersection(&image_box) else {
+            // nothing to do
+            return;
+        };
+
+        for y in isect.y_range() {
+            for x in isect.x_range() {
+                self.set_pixel(x as usize, y as usize, with.clone());
+            }
+        }
+    }
+
+    /// Copy image data from another bitmap with the same pixel format.
+    fn copy_from(
+        &mut self,
+        amap: &impl BitmapAccess<PF>,
+        amap_region: &math::PixelBox,
+        dst: &math::PixelPoint,
+    ) {
+        let Some((write_region, read_region)) = helpers::clip_to(
+            self.size(),
+            *dst,
+            amap.size(),
+            amap_region.min,
+            amap_region.size(),
+        ) else {
+            return;
+        };
+
+        let row_width = write_region.width() as usize * PF::PIXEL_WIDTH;
+        for y in 0..write_region.height() {
+            let write_offset = ((y + write_region.min.y) * self.row_stride() as i32) as usize;
+            let read_offset = ((y + read_region.min.y) * amap.row_stride() as i32) as usize;
+
+            let write_offset = write_offset + (write_region.min.x as usize) * PF::PIXEL_WIDTH;
+            let read_offset = read_offset + (read_region.min.x as usize) * PF::PIXEL_WIDTH;
+
+            self.data_mut()[write_offset..(write_offset + row_width)]
+                .copy_from_slice(&amap.data()[read_offset..(read_offset + row_width)]);
+        }
+    }
+}
+
+impl<PF: PixelFormat, T: BitmapMutAccess<PF> + Writable<PF>> Paintable<PF> for T {}
+
+/// A8-specific painting trait.
 pub trait AlphaPaintable: BitmapMutAccess<A8> + Writable<A8, ReadResult = u8> {
+    /*
     fn fill(&mut self, with: u8) {
         self.data_mut().fill(with);
     }
@@ -49,39 +109,15 @@ pub trait AlphaPaintable: BitmapMutAccess<A8> + Writable<A8, ReadResult = u8> {
                 .copy_from_slice(&amap.data()[read_offset..(read_offset + row_width)]);
         }
     }
+    */
 }
 
 impl<T: BitmapMutAccess<A8>> AlphaPaintable for T {}
 
-/// RGBA32-specific painting struct.
+/// RGBA32-specific painting trait.
 pub trait RgbaPaintable:
     BitmapAccess<Rgba32> + BitmapMutAccess<Rgba32> + Writable<Rgba32, ReadResult = Colour>
 {
-    /// Fill the entire image with a given colour.
-    fn fill(&mut self, col: Colour) {
-        for y in 0..self.height() {
-            for x in 0..self.width() {
-                self.set_pixel(x, y, col);
-            }
-        }
-    }
-
-    /// Fill a region with a given colour.
-    fn fill_region(&mut self, region: &math::PixelBox, col: Colour) {
-        let image_box =
-            math::PixelBox::from_origin_and_size(math::PixelPoint::origin(), self.size());
-        let Some(isect) = region.intersection(&image_box) else {
-            // nothing to do
-            return;
-        };
-
-        for y in isect.y_range() {
-            for x in isect.x_range() {
-                self.set_pixel(x as usize, y as usize, col);
-            }
-        }
-    }
-
     /// Fill a region with a given colour, using the values from an alphamap as the alpha value.
     fn fill_masked(
         &mut self,

+ 1 - 4
src/ops/helpers.rs

@@ -1,4 +1,4 @@
-use crate::{formats::PixelFormat, math, BitmapAccess};
+use crate::math;
 
 pub fn clip_to(
     img1_size: math::PixelSize,
@@ -29,6 +29,3 @@ pub fn clip_to(
         math::PixelBox::from_origin_and_size(pt2, sz).inner_box(adj),
     ))
 }
-
-#[test]
-fn clip_test() {}

+ 1 - 1
src/ops/impls.rs

@@ -18,7 +18,7 @@ impl<T: BitmapMutAccess<A8>> Writable<A8> for T {
 impl<T: BitmapAccess<Rgba32>> Readable<Rgba32> for T {
     type ReadResult = Colour;
     fn get_pixel(&self, x: usize, y: usize) -> Colour {
-        let index = (x + (y * self.row_stride())) * Rgba32::PIXEL_WIDTH;
+        let index = (x * Rgba32::PIXEL_WIDTH) + (y * self.row_stride());
         Colour::from_le_bytes(&self.data()[index..(index + 4)])
     }
 }