embedded_graphics/
framebuffer.rs

1//! Framebuffer.
2
3use core::{convert::Infallible, marker::PhantomData};
4
5use crate::{
6    draw_target::DrawTarget,
7    geometry::{OriginDimensions, Point, Size},
8    image::{GetPixel, ImageRaw},
9    iterator::raw::RawDataSlice,
10    pixelcolor::{
11        raw::{
12            BigEndian, ByteOrder, LittleEndian, RawData, RawU1, RawU16, RawU2, RawU24, RawU32,
13            RawU4, RawU8, ToBytes,
14        },
15        PixelColor,
16    },
17    Pixel,
18};
19
20/// Calculates the required buffer size.
21///
22/// This function is a workaround for current limitations in Rust const generics.
23/// It can be used to calculate the `N` parameter based on the size and color type of the framebuffer.
24pub const fn buffer_size<C: PixelColor>(width: usize, height: usize) -> usize {
25    buffer_size_bpp(width, height, C::Raw::BITS_PER_PIXEL)
26}
27
28/// Calculates the required buffer size.
29///
30/// This function is a workaround for current limitations in Rust const generics.
31/// It can be used to calculate the `N` parameter based on the size and bit depth of the framebuffer.
32pub const fn buffer_size_bpp(width: usize, height: usize, bpp: usize) -> usize {
33    (width * bpp + 7) / 8 * height
34}
35
36/// A framebuffer.
37///
38/// # Examples
39///
40/// ```
41/// use embedded_graphics::{
42///     framebuffer,
43///     framebuffer::{Framebuffer, buffer_size},
44///     pixelcolor::{Rgb565, raw::LittleEndian},
45///     prelude::*,
46///     primitives::PrimitiveStyle,
47/// };
48///
49/// let mut fb = Framebuffer::<Rgb565, _, LittleEndian, 320, 240, {buffer_size::<Rgb565>(320, 240)}>::new();
50///
51/// fb.bounding_box()
52///     .into_styled(PrimitiveStyle::with_stroke(Rgb565::RED, 1))
53///     .draw(&mut fb)
54///     .unwrap();
55/// ```
56#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
57pub struct Framebuffer<C, R, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> {
58    data: [u8; N],
59    color_type: PhantomData<C>,
60    raw_type: PhantomData<R>,
61    byte_order: PhantomData<BO>,
62    n_assert: (),
63}
64
65impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
66    Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>
67where
68    C: PixelColor,
69{
70    const BUFFER_SIZE: usize = buffer_size::<C>(WIDTH, HEIGHT);
71
72    /// Static assertion that N is correct.
73    // MSRV: remove N when constant generic expressions are stabilized
74    const CHECK_N: () = assert!(
75        N >= Self::BUFFER_SIZE,
76        "Invalid N: see Framebuffer documentation for more information"
77    );
78
79    /// Creates a new framebuffer.
80    pub const fn new() -> Self {
81        Self {
82            data: [0; N],
83            color_type: PhantomData,
84            raw_type: PhantomData,
85            byte_order: PhantomData,
86            n_assert: Self::CHECK_N,
87        }
88    }
89
90    /// Returns a reference to the raw framebuffer data.
91    pub const fn data(&self) -> &[u8; N] {
92        &self.data
93    }
94
95    /// Returns a mutable reference to the raw framebuffer data.
96    pub fn data_mut(&mut self) -> &mut [u8; N] {
97        &mut self.data
98    }
99}
100
101impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
102    Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>
103where
104    C: PixelColor + From<C::Raw>,
105    BO: ByteOrder,
106    for<'a> RawDataSlice<'a, C::Raw, BO>: IntoIterator<Item = C::Raw>,
107{
108    /// Returns an image based on the framebuffer content.
109    pub fn as_image(&self) -> ImageRaw<'_, C, BO> {
110        ImageRaw::new(&self.data[0..Self::BUFFER_SIZE], WIDTH as u32)
111    }
112}
113
114impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> GetPixel
115    for Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>
116where
117    C: PixelColor + From<C::Raw>,
118    BO: ByteOrder,
119    for<'a> RawDataSlice<'a, C::Raw, BO>: IntoIterator<Item = C::Raw>,
120{
121    type Color = C;
122
123    fn pixel(&self, p: Point) -> Option<C> {
124        self.as_image().pixel(p)
125    }
126}
127
128macro_rules! impl_bit {
129    ($raw_type:ident) => {
130        impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
131            Framebuffer<C, $raw_type, BO, WIDTH, HEIGHT, N>
132        where
133            C: PixelColor + Into<$raw_type>,
134        {
135            /// Sets the color of a pixel.
136            ///
137            /// Trying to set a pixel outside the framebuffer is a noop.
138            pub fn set_pixel(&mut self, p: Point, c: C) {
139                if let (Ok(x), Ok(y)) = (usize::try_from(p.x), usize::try_from(p.y)) {
140                    if x < WIDTH && y < HEIGHT {
141                        let pixels_per_bit = 8 / C::Raw::BITS_PER_PIXEL;
142                        let bits_per_row = WIDTH * C::Raw::BITS_PER_PIXEL;
143                        let bytes_per_row = (bits_per_row + 7) / 8;
144                        let byte_index = bytes_per_row * y + (x / pixels_per_bit);
145                        let bit_index = 8 - (x % pixels_per_bit + 1) * C::Raw::BITS_PER_PIXEL;
146
147                        let mask = !((2u8.pow(C::Raw::BITS_PER_PIXEL as u32) - 1) << bit_index);
148                        let bits = c.into().into_inner() << bit_index;
149
150                        self.data[byte_index] = self.data[byte_index] & mask | bits;
151                    }
152                }
153            }
154        }
155
156        impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DrawTarget
157            for Framebuffer<C, $raw_type, BO, WIDTH, HEIGHT, N>
158        where
159            C: PixelColor<Raw = $raw_type> + Into<$raw_type>,
160        {
161            type Color = C;
162            type Error = Infallible;
163
164            fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
165            where
166                I: IntoIterator<Item = Pixel<Self::Color>>,
167            {
168                for Pixel(p, c) in pixels {
169                    self.set_pixel(p, c);
170                }
171
172                Ok(())
173            }
174        }
175    };
176}
177
178impl_bit!(RawU1);
179impl_bit!(RawU2);
180impl_bit!(RawU4);
181
182impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
183    Framebuffer<C, RawU8, BO, WIDTH, HEIGHT, N>
184where
185    C: PixelColor + Into<RawU8>,
186{
187    /// Sets the color of a pixel.
188    ///
189    /// Setting a pixel outside the framebuffer's bounding box will be a noop.
190    pub fn set_pixel(&mut self, p: Point, c: C) {
191        if let (Ok(x), Ok(y)) = (usize::try_from(p.x), usize::try_from(p.y)) {
192            if x < WIDTH && y < HEIGHT {
193                let x = p.x as usize;
194                let y = p.y as usize;
195
196                self.data[y * WIDTH + x] = c.into().into_inner();
197            }
198        }
199    }
200}
201
202impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DrawTarget
203    for Framebuffer<C, RawU8, BO, WIDTH, HEIGHT, N>
204where
205    C: PixelColor<Raw = RawU8> + Into<RawU8>,
206{
207    type Color = C;
208    type Error = Infallible;
209
210    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
211    where
212        I: IntoIterator<Item = Pixel<Self::Color>>,
213    {
214        for Pixel(p, c) in pixels {
215            self.set_pixel(p, c);
216        }
217
218        Ok(())
219    }
220}
221
222macro_rules! impl_bytes {
223    ($raw_type:ty, $bo_type:ty, $to_bytes_fn:ident) => {
224        impl<C, const WIDTH: usize, const HEIGHT: usize, const N: usize>
225            Framebuffer<C, $raw_type, $bo_type, WIDTH, HEIGHT, N>
226        where
227            C: PixelColor + Into<$raw_type>,
228        {
229            /// Sets the color of a pixel.
230            ///
231            /// Trying to set a pixel outside the framebuffer is a noop.
232            pub fn set_pixel(&mut self, p: Point, c: C) {
233                const BYTES_PER_PIXEL: usize = <$raw_type>::BITS_PER_PIXEL / 8;
234
235                if let (Ok(x), Ok(y)) = (usize::try_from(p.x), usize::try_from(p.y)) {
236                    if x < WIDTH && y < HEIGHT {
237                        let x = p.x as usize;
238                        let y = p.y as usize;
239
240                        let index = (y * WIDTH + x) * BYTES_PER_PIXEL;
241
242                        self.data[index..index + BYTES_PER_PIXEL]
243                            .copy_from_slice(&c.into().$to_bytes_fn());
244                    }
245                }
246            }
247        }
248
249        impl<C, const WIDTH: usize, const HEIGHT: usize, const N: usize> DrawTarget
250            for Framebuffer<C, $raw_type, $bo_type, WIDTH, HEIGHT, N>
251        where
252            C: PixelColor<Raw = $raw_type> + Into<$raw_type>,
253        {
254            type Color = C;
255            type Error = Infallible;
256
257            fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
258            where
259                I: IntoIterator<Item = Pixel<Self::Color>>,
260            {
261                for Pixel(p, c) in pixels {
262                    self.set_pixel(p, c);
263                }
264
265                Ok(())
266            }
267        }
268    };
269
270    ($raw_type:ty) => {
271        impl_bytes!($raw_type, LittleEndian, to_le_bytes);
272        impl_bytes!($raw_type, BigEndian, to_be_bytes);
273    };
274}
275
276impl_bytes!(RawU16);
277impl_bytes!(RawU24);
278impl_bytes!(RawU32);
279
280impl<C, R, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> OriginDimensions
281    for Framebuffer<C, R, BO, WIDTH, HEIGHT, N>
282{
283    fn size(&self) -> Size {
284        Size::new(WIDTH as u32, HEIGHT as u32)
285    }
286}
287
288#[cfg(test)]
289mod tests {
290    use embedded_graphics_core::prelude::GrayColor;
291
292    use super::*;
293
294    use crate::{
295        geometry::Dimensions,
296        geometry::Point,
297        image::Image,
298        mock_display::MockDisplay,
299        pixelcolor::{BinaryColor, Gray2, Gray4, Gray8, Rgb565, Rgb888, RgbColor},
300        primitives::{Primitive, PrimitiveStyle},
301        Drawable,
302    };
303
304    /// Calculate the framebuffer generic constants.
305    macro_rules! framebuffer {
306        ($color_type:ty, $byte_order:ty, $width:expr, $height:expr) => {
307            $crate::framebuffer::Framebuffer::<
308                $color_type,
309                <$color_type as $crate::pixelcolor::PixelColor>::Raw,
310                $byte_order,
311                $width,
312                $height,
313                { $crate::framebuffer::buffer_size::<$color_type>($width, $height) },
314            >
315        };
316
317        ($color_type:ty, $width:expr, $height:expr) => {
318            $crate::framebuffer::Framebuffer::<
319                $color_type,
320                <$color_type as $crate::pixelcolor::PixelColor>::Raw,
321                $crate::pixelcolor::raw::LittleEndian,
322                $width,
323                $height,
324                { $crate::framebuffer::buffer_size::<$color_type>($width, $height) },
325            >
326        };
327    }
328
329    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
330    struct U32Color(u32);
331
332    impl PixelColor for U32Color {
333        type Raw = RawU32;
334    }
335
336    impl From<RawU32> for U32Color {
337        fn from(raw: RawU32) -> Self {
338            Self(raw.into_inner())
339        }
340    }
341
342    impl From<U32Color> for RawU32 {
343        fn from(color: U32Color) -> Self {
344            Self::new(color.0)
345        }
346    }
347
348    #[test]
349    fn raw_u1() {
350        let mut fb = <framebuffer!(BinaryColor, 9, 2)>::new();
351
352        use BinaryColor::{Off, On};
353        fb.draw_iter(
354            [
355                ((0, 0), On),  //
356                ((8, 1), On),  //
357                ((1, 1), On),  //
358                ((1, 1), Off), //
359                ((-1, 0), On), //
360                ((0, -1), On), //
361                ((9, 0), On),  //
362                ((0, 2), On),  //
363            ]
364            .iter()
365            .map(|(p, c)| Pixel(Point::from(*p), *c)),
366        )
367        .unwrap();
368
369        assert_eq!(
370            fb.data(),
371            &[
372                0b10000000, 0b00000000, //
373                0b00000000, 0b10000000, //
374            ]
375        );
376    }
377
378    #[test]
379    fn raw_u2() {
380        type FB = framebuffer!(Gray2, 6, 4);
381        let mut fb = FB::new();
382
383        fb.draw_iter(
384            [
385                ((0, 0), 1),  //
386                ((5, 3), 2),  //
387                ((1, 1), 3),  //
388                ((1, 2), 0),  //
389                ((-1, 0), 3), //
390                ((0, -1), 3), //
391                ((6, 0), 3),  //
392                ((0, 4), 3),  //
393            ]
394            .iter()
395            .map(|(p, c)| Pixel(Point::from(*p), Gray2::new(*c))),
396        )
397        .unwrap();
398
399        assert_eq!(
400            fb.data(),
401            &[
402                0b01000000, 0b00000000, //
403                0b00110000, 0b00000000, //
404                0b00000000, 0b00000000, //
405                0b00000000, 0b00100000, //
406            ]
407        );
408    }
409
410    #[test]
411    fn raw_u4() {
412        let mut fb = <framebuffer!(Gray4, 3, 2)>::new();
413
414        fb.draw_iter(
415            [
416                ((0, 0), 0x1),  //
417                ((2, 1), 0xF),  //
418                ((1, 0), 0xA),  //
419                ((1, 1), 0xB),  //
420                ((-1, 0), 0xF), //
421                ((0, -1), 0xF), //
422                ((3, 0), 0xF),  //
423                ((0, 2), 0xF),  //
424            ]
425            .iter()
426            .map(|(p, c)| Pixel(Point::from(*p), Gray4::new(*c))),
427        )
428        .unwrap();
429
430        assert_eq!(
431            fb.data(),
432            &[
433                0x1A, 0x00, //
434                0x0B, 0xF0, //
435            ]
436        );
437    }
438
439    #[test]
440    fn raw_u8() {
441        let mut fb = <framebuffer!(Gray8, 3, 2)>::new();
442
443        fb.draw_iter(
444            [
445                ((0, 0), 0x10),  //
446                ((2, 1), 0x22),  //
447                ((1, 0), 0x3F),  //
448                ((1, 1), 0xF0),  //
449                ((-1, 0), 0xFF), //
450                ((0, -1), 0xFF), //
451                ((3, 0), 0xFF),  //
452                ((0, 2), 0xFF),  //
453            ]
454            .iter()
455            .map(|(p, c)| Pixel(Point::from(*p), Gray8::new(*c))),
456        )
457        .unwrap();
458
459        assert_eq!(
460            fb.data(),
461            &[
462                0x10, 0x3F, 0x00, //
463                0x00, 0xF0, 0x22, //
464            ]
465        );
466    }
467
468    #[test]
469    fn raw_u16_le() {
470        let mut fb = <framebuffer!(Rgb565, 3, 2)>::new();
471
472        fb.draw_iter(
473            [
474                ((0, 0), 0x1000),  //
475                ((2, 1), 0x0001),  //
476                ((1, 0), 0x1234),  //
477                ((1, 1), 0x8765),  //
478                ((-1, 0), 0xFFFF), //
479                ((0, -1), 0xFFFF), //
480                ((3, 0), 0xFFFF),  //
481                ((0, 2), 0xFFFF),  //
482            ]
483            .iter()
484            .map(|(p, c)| Pixel(Point::from(*p), Rgb565::from(RawU16::new(*c)))),
485        )
486        .unwrap();
487
488        assert_eq!(
489            fb.data(),
490            &[
491                0x00, 0x10, 0x34, 0x12, 0x00, 0x00, //
492                0x00, 0x00, 0x65, 0x87, 0x01, 0x00, //
493            ]
494        );
495    }
496
497    #[test]
498    fn raw_u16_be() {
499        let mut fb = <framebuffer!(Rgb565, BigEndian, 3, 2)>::new();
500
501        fb.draw_iter(
502            [
503                ((0, 0), 0x1000),  //
504                ((2, 1), 0x0001),  //
505                ((1, 0), 0x1234),  //
506                ((1, 1), 0x8765),  //
507                ((-1, 0), 0xFFFF), //
508                ((0, -1), 0xFFFF), //
509                ((3, 0), 0xFFFF),  //
510                ((0, 2), 0xFFFF),  //
511            ]
512            .iter()
513            .map(|(p, c)| Pixel(Point::from(*p), Rgb565::from(RawU16::new(*c)))),
514        )
515        .unwrap();
516
517        assert_eq!(
518            fb.data(),
519            &[
520                0x10, 0x00, 0x12, 0x34, 0x00, 0x00, //
521                0x00, 0x00, 0x87, 0x65, 0x00, 0x01, //
522            ]
523        );
524    }
525
526    #[test]
527    fn raw_u24_le() {
528        let mut fb = <framebuffer!(Rgb888, 3, 2)>::new();
529
530        fb.draw_iter(
531            [
532                ((0, 0), 0x100000),  //
533                ((2, 1), 0x000001),  //
534                ((1, 0), 0x123456),  //
535                ((1, 1), 0x876543),  //
536                ((-1, 0), 0xFFFFFF), //
537                ((0, -1), 0xFFFFFF), //
538                ((3, 0), 0xFFFFFF),  //
539                ((0, 2), 0xFFFFFF),  //
540            ]
541            .iter()
542            .map(|(p, c)| Pixel(Point::from(*p), Rgb888::from(RawU24::new(*c)))),
543        )
544        .unwrap();
545
546        assert_eq!(
547            fb.data(),
548            &[
549                0x00, 0x00, 0x10, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, //
550                0x00, 0x00, 0x00, 0x43, 0x65, 0x87, 0x01, 0x00, 0x00, //
551            ]
552        );
553    }
554
555    #[test]
556    fn raw_u24_be() {
557        let mut fb = <framebuffer!(Rgb888, BigEndian, 3, 2)>::new();
558
559        fb.draw_iter(
560            [
561                ((0, 0), 0x100000),  //
562                ((2, 1), 0x000001),  //
563                ((1, 0), 0x123456),  //
564                ((1, 1), 0x876543),  //
565                ((-1, 0), 0xFFFFFF), //
566                ((0, -1), 0xFFFFFF), //
567                ((3, 0), 0xFFFFFF),  //
568                ((0, 2), 0xFFFFFF),  //
569            ]
570            .iter()
571            .map(|(p, c)| Pixel(Point::from(*p), Rgb888::from(RawU24::new(*c)))),
572        )
573        .unwrap();
574
575        assert_eq!(
576            fb.data(),
577            &[
578                0x10, 0x00, 0x00, 0x12, 0x34, 0x56, 0x00, 0x00, 0x00, //
579                0x00, 0x00, 0x00, 0x87, 0x65, 0x43, 0x00, 0x00, 0x01, //
580            ]
581        );
582    }
583
584    #[test]
585    fn raw_u32_le() {
586        let mut fb = <framebuffer!(U32Color, 3, 2)>::new();
587
588        fb.draw_iter(
589            [
590                ((0, 0), 0x10000000),  //
591                ((2, 1), 0x00000001),  //
592                ((1, 0), 0x12345678),  //
593                ((1, 1), 0x87654321),  //
594                ((-1, 0), 0xFFFFFFFF), //
595                ((0, -1), 0xFFFFFFFF), //
596                ((3, 0), 0xFFFFFFFF),  //
597                ((0, 2), 0xFFFFFFFF),  //
598            ]
599            .iter()
600            .map(|(p, c)| Pixel(Point::from(*p), U32Color::from(RawU32::new(*c)))),
601        )
602        .unwrap();
603
604        assert_eq!(
605            fb.data(),
606            &[
607                0x00, 0x00, 0x00, 0x10, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, //
608                0x00, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x01, 0x00, 0x00, 0x00, //
609            ]
610        );
611    }
612
613    #[test]
614    fn raw_u32_be() {
615        let mut fb = <framebuffer!(U32Color, BigEndian, 3, 2)>::new();
616
617        fb.draw_iter(
618            [
619                ((0, 0), 0x10000000),  //
620                ((2, 1), 0x00000001),  //
621                ((1, 0), 0x12345678),  //
622                ((1, 1), 0x87654321),  //
623                ((-1, 0), 0xFFFFFFFF), //
624                ((0, -1), 0xFFFFFFFF), //
625                ((3, 0), 0xFFFFFFFF),  //
626                ((0, 2), 0xFFFFFFFF),  //
627            ]
628            .iter()
629            .map(|(p, c)| Pixel(Point::from(*p), U32Color::from(RawU32::new(*c)))),
630        )
631        .unwrap();
632
633        assert_eq!(
634            fb.data(),
635            &[
636                0x10, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, //
637                0x00, 0x00, 0x00, 0x00, 0x87, 0x65, 0x43, 0x21, 0x00, 0x00, 0x00, 0x01, //
638            ]
639        );
640    }
641
642    #[test]
643    fn as_image() {
644        let mut fb = <framebuffer!(BinaryColor, 10, 10)>::new();
645
646        fb.bounding_box()
647            .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
648            .draw(&mut fb)
649            .unwrap();
650
651        fb.draw_iter(
652            [(7, 2), (8, 8)]
653                .into_iter()
654                .map(|p| Pixel(Point::from(p), BinaryColor::On)),
655        )
656        .unwrap();
657
658        let mut display = MockDisplay::<BinaryColor>::new();
659        Image::new(&fb.as_image(), Point::new(2, 1))
660            .draw(&mut display)
661            .unwrap();
662
663        display.assert_pattern(&[
664            "            ",
665            "  ##########",
666            "  #........#",
667            "  #......#.#",
668            "  #........#",
669            "  #........#",
670            "  #........#",
671            "  #........#",
672            "  #........#",
673            "  #.......##",
674            "  ##########",
675        ]);
676    }
677
678    #[test]
679    fn pixel() {
680        let mut fb = <framebuffer!(BinaryColor, 10, 10)>::new();
681
682        fb.draw_iter(
683            [(7, 2), (8, 8)]
684                .into_iter()
685                .map(|p| Pixel(Point::from(p), BinaryColor::On)),
686        )
687        .unwrap();
688
689        let expected = [
690            ((0, 0), Some(BinaryColor::Off)),
691            ((1, 0), Some(BinaryColor::Off)),
692            ((1, 1), Some(BinaryColor::Off)),
693            ((7, 2), Some(BinaryColor::On)),
694            ((8, 8), Some(BinaryColor::On)),
695            ((-1, 0), None),
696            ((0, -1), None),
697            ((10, 0), None),
698            ((0, 10), None),
699        ];
700        for (p, c) in expected {
701            assert_eq!(fb.pixel(p.into()), c, "{p:?}");
702        }
703    }
704
705    #[test]
706    fn set_pixel() {
707        // This tests only checks that the set_pixel methods are present for all BPPs.
708        // The correct function is tested indirectly in the DrawTarget tests.
709
710        <framebuffer!(BinaryColor, 10, 10)>::new().set_pixel(Point::zero(), BinaryColor::On);
711        <framebuffer!(Gray2, 10, 10)>::new().set_pixel(Point::zero(), Gray2::WHITE);
712        <framebuffer!(Gray4, 10, 10)>::new().set_pixel(Point::zero(), Gray4::WHITE);
713        <framebuffer!(Gray8, 10, 10)>::new().set_pixel(Point::zero(), Gray8::WHITE);
714        <framebuffer!(Rgb565, 10, 10)>::new().set_pixel(Point::zero(), Rgb565::WHITE);
715        <framebuffer!(Rgb888, 10, 10)>::new().set_pixel(Point::zero(), Rgb888::WHITE);
716        <framebuffer!(U32Color, 10, 10)>::new().set_pixel(Point::zero(), U32Color(0));
717    }
718
719    #[test]
720    fn oversized_buffer() {
721        let fb = Framebuffer::<
722            BinaryColor,
723            _,
724            LittleEndian,
725            10,
726            5,
727            { buffer_size::<BinaryColor>(10, 5) * 3 / 2 },
728        >::new();
729
730        assert_eq!(fb.size(), Size::new(10, 5));
731        assert_eq!(fb.as_image().size(), Size::new(10, 5));
732
733        let outside_x = Point::zero() + fb.size().x_axis();
734        let outside_y = Point::zero() + fb.size().y_axis();
735
736        assert_eq!(fb.pixel(outside_x), None);
737        assert_eq!(fb.pixel(outside_y), None);
738
739        let mut fb2 = fb.clone();
740        fb2.set_pixel(outside_x, BinaryColor::On);
741        fb2.set_pixel(outside_y, BinaryColor::On);
742
743        assert_eq!(fb, fb2);
744    }
745}