ibm437 0.4.0

IBM437 bitmap font — works with embedded-graphics and raw framebuffers (minifb, softbuffer, SDL2…)
Documentation
#![cfg_attr(not(test), no_std)]

// ─── Core: character mapping (always available) ───────────────────────
pub mod char_offset;
pub use char_offset::{CHARS_PER_ROW, char_offset_impl};

// ─── Raw font data (always available) ─────────────────────────────────

/// Raw 1-bit-per-pixel bitmap for the 8×8 regular font.
///
/// The spritesheet is laid out as 16 glyphs per row, 16 rows.
/// Total: 2 048 bytes.
#[cfg(feature = "regular8x8")]
pub const IBM437_8X8_REGULAR_DATA: &[u8] = include_bytes!("fonts/ibm437_font_8_8_regular.raw");

/// Raw 1-bit-per-pixel bitmap for the 8×8 bold font.
#[cfg(feature = "bold8x8")]
pub const IBM437_8X8_BOLD_DATA: &[u8] = include_bytes!("fonts/ibm437_font_8_8_bold.raw");

/// Raw 1-bit-per-pixel bitmap for the 9×14 regular font.
#[cfg(feature = "regular9x14")]
pub const IBM437_9X14_REGULAR_DATA: &[u8] = include_bytes!("fonts/ibm437_font_9_14_regular.raw");

// ─── embedded-graphics backend ────────────────────────────────────────

#[cfg(feature = "embedded-graphics-backend")]
mod eg_backend {
    use embedded_graphics::{
        geometry::Size,
        image::ImageRaw,
        mono_font::{DecorationDimensions, MonoFont},
    };

    use crate::char_offset::{CHARS_PER_ROW, char_offset_impl};

    /// The 8×8 regular [`MonoFont`] for embedded-graphics.
    ///
    /// [![8×8 regular font spritemap screenshot](https://codeberg.org/sbechet/ibm437/raw/branch/master/doc/ibm437_font_8_8_regular.png)](https://codeberg.org/sbechet/ibm437/raw/branch/master/doc/ibm437_font_8_8_regular.png)
    #[cfg(feature = "regular8x8")]
    pub const IBM437_8X8_REGULAR: MonoFont = MonoFont {
        image: ImageRaw::new(
            include_bytes!("fonts/ibm437_font_8_8_regular.raw"),
            CHARS_PER_ROW as u32 * 8,
        ),
        glyph_mapping: &char_offset_impl,
        character_size: Size::new(8, 8),
        character_spacing: 0,
        baseline: 6,
        underline: DecorationDimensions::new(8, 1),
        strikethrough: DecorationDimensions::default_strikethrough(8),
    };

    /// The 8×8 bold [`MonoFont`] for embedded-graphics.
    ///
    /// [![8×8 bold font spritemap screenshot](https://codeberg.org/sbechet/ibm437/raw/branch/master/doc/ibm437_font_8_8_bold.png)](https://codeberg.org/sbechet/ibm437/raw/branch/master/doc/ibm437_font_8_8_bold.png)
    #[cfg(feature = "bold8x8")]
    pub const IBM437_8X8_BOLD: MonoFont = MonoFont {
        image: ImageRaw::new(
            include_bytes!("fonts/ibm437_font_8_8_bold.raw"),
            CHARS_PER_ROW as u32 * 8,
        ),
        glyph_mapping: &char_offset_impl,
        character_size: Size::new(8, 8),
        character_spacing: 0,
        baseline: 6,
        underline: DecorationDimensions::new(8, 1),
        strikethrough: DecorationDimensions::default_strikethrough(8),
    };

    /// The 9×14 regular [`MonoFont`] for embedded-graphics.
    ///
    /// [![9×14 regular font spritemap screenshot](https://codeberg.org/sbechet/ibm437/raw/branch/master/doc/ibm437_font_9_14_regular.png)](https://codeberg.org/sbechet/ibm437/raw/branch/master/doc/ibm437_font_9_14_regular.png)
    #[cfg(feature = "regular9x14")]
    pub const IBM437_9X14_REGULAR: MonoFont = MonoFont {
        image: ImageRaw::new(
            include_bytes!("fonts/ibm437_font_9_14_regular.raw"),
            CHARS_PER_ROW as u32 * 9,
        ),
        glyph_mapping: &char_offset_impl,
        character_size: Size::new(9, 14),
        character_spacing: 0,
        baseline: 10,
        underline: DecorationDimensions::new(14, 1),
        strikethrough: DecorationDimensions::default_strikethrough(14),
    };
}

#[cfg(feature = "embedded-graphics-backend")]
pub use eg_backend::*;

// ─── Framebuffer backend ──────────────────────────────────────────────

#[cfg(feature = "framebuffer")]
pub mod framebuffer;

// ─── Tests ────────────────────────────────────────────────────────────

#[cfg(all(test, feature = "embedded-graphics-backend"))]
mod test {
    use super::*;
    use embedded_graphics::{
        mock_display::MockDisplay,
        mono_font::{MonoTextStyle, MonoTextStyleBuilder},
        pixelcolor::BinaryColor,
        prelude::*,
        text::Text,
    };

    #[test]
    fn test_a() {
        let mut display = MockDisplay::new();

        assert_eq!(char_offset_impl('a'), 'a' as usize);

        let style = MonoTextStyle::new(&IBM437_8X8_REGULAR, BinaryColor::On);

        Text::new("a", Point::new(0, 6), style)
            .draw(&mut display)
            .unwrap();

        assert_eq!(
            display,
            MockDisplay::from_pattern(&[
                "            ",
                "            ",
                "  ####      ",
                "      #     ",
                "  #####     ",
                " #    #     ",
                "  ######    ",
                "            ",
            ])
        );
    }

    #[test]
    fn test_nbsp() {
        let mut display = MockDisplay::new();

        assert_eq!(char_offset_impl('\u{A0}'), '\u{A0}' as usize);

        let style = MonoTextStyleBuilder::new()
            .font(&IBM437_8X8_REGULAR)
            .text_color(BinaryColor::On)
            .background_color(BinaryColor::Off)
            .build();

        Text::new("\u{A0}", Point::new(0, 6), style)
            .draw(&mut display)
            .unwrap();

        assert_eq!(
            display,
            MockDisplay::from_pattern(&[
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
            ])
        );
    }

    #[test]
    fn test_space() {
        let mut display = MockDisplay::new();

        assert_eq!(char_offset_impl(' '), ' ' as usize);

        let style = MonoTextStyleBuilder::new()
            .font(&IBM437_8X8_REGULAR)
            .text_color(BinaryColor::On)
            .background_color(BinaryColor::Off)
            .build();

        Text::new(" ", Point::new(0, 6), style)
            .draw(&mut display)
            .unwrap();

        assert_eq!(
            display,
            MockDisplay::from_pattern(&[
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
                "........     ",
            ])
        );
    }
}