multi_mono_font/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#![no_std]

mod char_size;
mod draw_target;
mod generated;
pub mod mapping;
mod multi_mono_text_style;
mod static_text;
mod sub_image;

use core::fmt;

pub use char_size::CharSize;
pub use generated::*;
use mapping::StrGlyphMapping;
pub use multi_mono_text_style::{
    MultiMonoLineHeight, MultiMonoTextStyle, MultiMonoTextStyleBuilder,
};
pub use static_text::StaticText;

use embedded_graphics::{
    geometry::{OriginDimensions, Point},
    image::ImageRaw,
    pixelcolor::BinaryColor,
    primitives::Rectangle,
};
use sub_image::SubImage;

#[cfg(not(feature = "big-character-size"))]
pub type ChSzTy = u8;
#[cfg(feature = "big-character-size")]
pub type ChSzTy = u16;

/// Monospaced bitmap font.
///
/// See the [module documentation] for more information about using fonts.
///
/// [module documentation]: self
#[derive(Clone, Copy)]
pub struct MultiMonoFont<'a> {
    /// Raw image data containing the font.
    pub image: ImageRaw<'a, BinaryColor>,

    /// Size of a single character in pixel.
    pub character_size: CharSize,

    /// Spacing between characters.
    ///
    /// The spacing defines how many empty pixels are added horizontally between adjacent characters
    /// on a single line of text.
    pub character_spacing: ChSzTy,

    /// The baseline.
    ///
    /// Offset from the top of the glyph bounding box to the baseline.
    pub baseline: ChSzTy,

    /// Glyph mapping.
    pub glyph_mapping: &'a StrGlyphMapping<'a>,
}

impl MultiMonoFont<'_> {
    /// Returns a subimage for a glyph.
    pub(crate) fn glyph(&self, c: char) -> SubImage<'_, ImageRaw<BinaryColor>> {
        if self.character_size.width == 0
            || self.image.size().width < self.character_size.width as u32
        {
            return SubImage::new_unchecked(&self.image, Rectangle::zero());
        }

        let glyphs_per_row = self.image.size().width / self.character_size.width as u32;

        // Char _code_ offset from first char, most often a space
        // E.g. first char = ' ' (32), target char = '!' (33), offset = 33 - 32 = 1
        let glyph_index = self.glyph_mapping.index(c) as u32;
        let row = glyph_index / glyphs_per_row;

        // Top left corner of character, in pixels
        let char_x = (glyph_index - (row * glyphs_per_row)) * self.character_size.width as u32;
        let char_y = row * self.character_size.height as u32;

        SubImage::new_unchecked(
            &self.image,
            Rectangle::new(
                Point::new(char_x as i32, char_y as i32),
                self.character_size.size(),
            ),
        )
    }
}

impl PartialEq for MultiMonoFont<'_> {
    #[allow(trivial_casts)]
    fn eq(&self, other: &Self) -> bool {
        self.image == other.image
            && self.character_size == other.character_size
            && self.character_spacing == other.character_spacing
            && self.baseline == other.baseline
            && core::ptr::eq(self.glyph_mapping, other.glyph_mapping)
    }
}

impl fmt::Debug for MultiMonoFont<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("MultiMonoFont")
            .field("image", &self.image)
            .field("character_size", &self.character_size)
            .field("character_spacing", &self.character_spacing)
            .field("baseline", &self.baseline)
            .field("glyph_mapping", &"?")
            .finish_non_exhaustive()
    }
}

#[cfg(feature = "defmt")]
impl ::defmt::Format for MultiMonoFont<'_> {
    fn format(&self, f: ::defmt::Formatter) {
        ::defmt::write!(
            f,
            "MultiMonoFont {{ image: {}, character_size: {}, character_spacing: {}, baseline: {}, strikethrough: {}, underline: {}, .. }}",
            &self.image,
            &self.character_size,
            &self.character_spacing,
            &self.baseline,
            &self.strikethrough,
            &self.underline,

        )
    }
}

const NULL_FONT: MultiMonoFont = MultiMonoFont {
    image: ImageRaw::new(&[], 1),
    character_size: CharSize::zero(),
    character_spacing: 0,
    baseline: 0,
    glyph_mapping: &StrGlyphMapping::new("", 0),
};