signed_distance_field/
binary_image.rs

1
2/// Represents an image with each pixel being either true or false,
3/// corresponding to inside-the-shape and outside-of-the-shape respectively.
4/// BinaryImages can be created from byte slices
5/// or piston images if the feature `piston_image` is activated.
6pub trait BinaryImage {
7    #[inline]
8    fn width(&self) -> u16;
9
10    #[inline]
11    fn height(&self) -> u16;
12
13    #[inline(always)]
14    fn is_inside(&self, x: u16, y: u16) -> bool;
15}
16
17/// An image which is described by a row major slice of bytes, with one byte per pixel.
18/// To determine if a byte is inside or outside,
19/// it is compared to a threshold. The default threshold is 127.
20pub struct BinaryByteSliceImage<'b> {
21    width: u16,
22    height: u16,
23
24    /// A row-major image vector with one byte per pixel.
25    buffer: &'b [u8],
26
27    /// A pixel must be brighter than this value
28    /// in order to be inside the shape.
29    threshold: u8,
30}
31
32/// Create a binary image from a row major byte slice with each byte brighter than 127 being "inside-the-shape"
33pub fn of_byte_slice(buffer: &[u8], width: u16, height: u16) -> BinaryByteSliceImage {
34    of_byte_slice_with_threshold(buffer, width, height, 127)
35}
36
37/// Create a binary image from a row major byte slice with each byte brighter than the threshold being "inside-the-shape"
38pub fn of_byte_slice_with_threshold(buffer: &[u8], width: u16, height: u16, threshold: u8) -> BinaryByteSliceImage {
39    debug_assert_eq!(buffer.len(), width as usize * height as usize, "Buffer dimension mismatch");
40    BinaryByteSliceImage { width, height, buffer, threshold }
41}
42
43
44impl BinaryImage for BinaryByteSliceImage<'_> {
45    #[inline]
46    fn width(&self) -> u16 {
47        self.width
48    }
49
50    #[inline]
51    fn height(&self) -> u16 {
52        self.height
53    }
54
55    #[inline]
56    fn is_inside(&self, x: u16, y: u16) -> bool {
57        self.buffer[self.width as usize * y as usize + x as usize] > self.threshold
58    }
59}
60
61
62/// Create binary images from piston images.
63#[cfg(feature = "piston_image")]
64pub mod piston_image {
65    use image::*;
66    use super::BinaryImage;
67
68    /// Create a binary image from a grey-scale piston image
69    /// with all pixels brighter than 127 being inside-the-shape.
70    pub fn of_gray_image(image: &GrayImage) -> GrayBinaryImage<u8, Vec<u8>> {
71        of_gray_image_with_threshold(image, 127)
72    }
73
74    /// Create a binary image from a grey-scale piston image
75    /// with all pixels brighter than the threshold being inside-the-shape.
76    pub fn of_gray_image_with_threshold(image: &GrayImage, threshold: u8)
77        -> GrayBinaryImage<u8, Vec<u8>>
78    {
79        GrayBinaryImage { image, threshold }
80    }
81
82
83    /// A binary image constructed from a grey-scale piston image
84    pub struct GrayBinaryImage<'i, P: 'static + Primitive, Container> {
85        image: &'i ImageBuffer<Luma<P>, Container>,
86        threshold: P,
87    }
88
89    impl<'i, P, C> BinaryImage for GrayBinaryImage<'i, P, C>
90        where P: 'static + Primitive, C: std::ops::Deref<Target = [P]>
91    {
92        fn width(&self) -> u16 {
93            self.image.width() as u16
94        }
95
96        fn height(&self) -> u16 {
97            self.image.height() as u16
98        }
99
100        fn is_inside(&self, x: u16, y: u16) -> bool {
101            self.image.get_pixel(x as u32, y as u32).data[0] > self.threshold
102        }
103    }
104
105}
106