noto_sans_mono_bitmap/
lib.rs

1//! Provides pre-rasterized characters from the "Noto Sans Mono" font in different sizes and font
2//! weights for multiple unicode ranges. This crate is `no_std` and needs no allocations or floating
3//! point operations. Useful in kernels and bootloaders when only "soft-float" is available. Strictly
4//! speaking, this crate is more than a basic bitmap font, because it encodes each pixel as a byte
5//! and not as a bit, which results in a much nicer result on the screen.
6//!
7//! * Original font files taken from: <https://fonts.google.com/noto/specimen/Noto+Sans+Mono>
8//! * License: SIL Open Font License (OFL) <https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL>
9//!
10//! ## TL;DR
11//! * ✅ `no_std`, zero allocations, no floating point operations
12//! * ✅ most important symbols, numbers, and letters as pre-rasterized constant. Unicode-ranges are selectable.
13//! * ✅ Noto Sans Mono font as base
14//! * ✅ different sizes and font weights (light, normal, bold)
15//! * ✅ nice anti-aliasing/smoothing and better looking than legacy bitmap fonts
16//! * ✅ every pixel is encoded in a byte (0-255) and not a bit, which results in a much nicer result on the screen.
17//! * ✅ relevant font sizes, such as 14, 18, 22, and 32px (as optional build time features)
18//! * ✅ zero dependencies
19//! * ✅ All characters are aligned in their box/raster. If they are printed next to each other, the result looks nice.
20//!
21//! Please check [README.md](https://github.com/phip1611/noto-sans-mono-bitmap-rs/blob/main/README.md)
22//! for more details.
23
24// # THIS FILE IS AUTO GENERATED BY THE PROJECT IN "../codegen" (see repository!)
25
26#![no_std]
27#![deny(
28    clippy::all,
29    clippy::cargo,
30    clippy::nursery,
31    // clippy::restriction,
32    // clippy::pedantic
33)]
34// now allow a few rules which are denied by the above statement
35// --> they are ridiculous and not necessary
36#![allow(
37    clippy::suboptimal_flops,
38    clippy::redundant_pub_crate,
39    clippy::fallible_impl_from,
40    clippy::large_stack_frames
41)]
42#![deny(missing_debug_implementations)]
43#![deny(rustdoc::all)]
44
45// # THIS FILE IS AUTO GENERATED BY THE PROJECT IN "../codegen" (see repository!)
46
47mod bold;
48mod light;
49mod regular;
50
51/// Describes the relevant information for a rendered char of the font.
52#[derive(Debug)]
53pub struct RasterizedChar {
54    /// The actual font data that is `height` * `width` bytes in size.
55    /// Each byte describes the intensity of a pixel from 0 to 255.
56    raster: &'static [&'static [u8]],
57    /// Height of the raster box. The actual font size is slightly smaller.
58    height: usize,
59    /// The width of the rasterized char. It is guaranteed, that all chars
60    /// of the same font weight and raster height also have the same width
61    /// (as you would expect from a mono font.)
62    width: usize,
63}
64
65impl RasterizedChar {
66    /// The actual font data that is `height` * `width` bytes in size.
67    /// Each byte describes the intensity of a pixel from 0 to 255.
68    #[inline]
69    pub const fn raster(&self) -> &'static [&'static [u8]] {
70        self.raster
71    }
72
73    /// Height of the raster box. The actual font size is slightly smaller.
74    #[inline]
75    pub const fn height(&self) -> usize {
76        self.height
77    }
78
79    /// The width of the raster char. It is guaranteed, that all chars
80    /// of the same font weight and raster height also have the same width
81    /// (as you would expect from a mono font).
82    #[inline]
83    pub const fn width(&self) -> usize {
84        self.width
85    }
86}
87
88/// Supported font weights.
89///
90/// The available variants depend on the selected Cargo build features.
91#[derive(Debug, Copy, Clone)]
92#[repr(usize)]
93pub enum FontWeight {
94    #[cfg(feature = "light")]
95    Light,
96    #[cfg(feature = "regular")]
97    Regular,
98    #[cfg(feature = "bold")]
99    Bold,
100}
101
102impl FontWeight {
103    /// Returns the numeric value of the enum variant.
104    #[inline]
105    pub const fn val(self) -> usize {
106        self as _
107    }
108}
109
110/// The height of the pre-rasterized font.
111///
112/// The font size will be a few percent less, because each letter contains
113/// vertical padding for proper alignment of chars (i.e. ÄyA). The width of
114/// each character will be also less than the height, because there is no
115/// horizontal padding included.
116///
117/// The available variants depend on the selected Cargo build features.
118#[derive(Debug, Clone, Copy)]
119#[repr(usize)]
120pub enum RasterHeight {
121    #[cfg(feature = "size_16")]
122    Size16 = 16,
123    #[cfg(feature = "size_20")]
124    Size20 = 20,
125    #[cfg(feature = "size_24")]
126    Size24 = 24,
127    #[cfg(feature = "size_32")]
128    Size32 = 32,
129}
130
131impl RasterHeight {
132    /// Returns the numeric value of the variant.
133    #[inline]
134    pub const fn val(self) -> usize {
135        self as _
136    }
137}
138
139/// Returns a [`RasterizedChar`] for the given char, [`FontWeight`], and [`RasterHeight`].
140///
141/// Returns None, if the given char is not known by the font. In this case,
142/// you could fall back to `get_raster(' ', ...)`.
143#[inline]
144pub fn get_raster(c: char, style: FontWeight, size: RasterHeight) -> Option<RasterizedChar> {
145    let raster = match style {
146        #[cfg(feature = "light")]
147        FontWeight::Light => match size {
148            #[cfg(feature = "size_16")]
149            RasterHeight::Size16 => crate::light::size_16::get_char(c),
150            #[cfg(feature = "size_20")]
151            RasterHeight::Size20 => crate::light::size_20::get_char(c),
152            #[cfg(feature = "size_24")]
153            RasterHeight::Size24 => crate::light::size_24::get_char(c),
154            #[cfg(feature = "size_32")]
155            RasterHeight::Size32 => crate::light::size_32::get_char(c),
156        },
157        #[cfg(feature = "regular")]
158        FontWeight::Regular => match size {
159            #[cfg(feature = "size_16")]
160            RasterHeight::Size16 => crate::regular::size_16::get_char(c),
161            #[cfg(feature = "size_20")]
162            RasterHeight::Size20 => crate::regular::size_20::get_char(c),
163            #[cfg(feature = "size_24")]
164            RasterHeight::Size24 => crate::regular::size_24::get_char(c),
165            #[cfg(feature = "size_32")]
166            RasterHeight::Size32 => crate::regular::size_32::get_char(c),
167        },
168        #[cfg(feature = "bold")]
169        FontWeight::Bold => match size {
170            #[cfg(feature = "size_16")]
171            RasterHeight::Size16 => crate::bold::size_16::get_char(c),
172            #[cfg(feature = "size_20")]
173            RasterHeight::Size20 => crate::bold::size_20::get_char(c),
174            #[cfg(feature = "size_24")]
175            RasterHeight::Size24 => crate::bold::size_24::get_char(c),
176            #[cfg(feature = "size_32")]
177            RasterHeight::Size32 => crate::bold::size_32::get_char(c),
178        },
179    };
180
181    raster.map(|raster| RasterizedChar {
182        raster,
183        height: size.val(),
184        width: get_raster_width(style, size),
185    })
186}
187
188/// Returns the width in pixels a char will occupy on the screen.
189///
190/// The width is constant for all characters regarding the same combination
191/// of [`FontWeight`] and [`RasterHeight`]. The width is a few percent smaller
192/// than the height of each char
193#[inline]
194pub const fn get_raster_width(style: FontWeight, size: RasterHeight) -> usize {
195    match style {
196        #[cfg(feature = "light")]
197        FontWeight::Light => match size {
198            #[cfg(feature = "size_16")]
199            RasterHeight::Size16 => crate::light::size_16::RASTER_WIDTH,
200            #[cfg(feature = "size_20")]
201            RasterHeight::Size20 => crate::light::size_20::RASTER_WIDTH,
202            #[cfg(feature = "size_24")]
203            RasterHeight::Size24 => crate::light::size_24::RASTER_WIDTH,
204            #[cfg(feature = "size_32")]
205            RasterHeight::Size32 => crate::light::size_32::RASTER_WIDTH,
206        },
207        #[cfg(feature = "regular")]
208        FontWeight::Regular => match size {
209            #[cfg(feature = "size_16")]
210            RasterHeight::Size16 => crate::regular::size_16::RASTER_WIDTH,
211            #[cfg(feature = "size_20")]
212            RasterHeight::Size20 => crate::regular::size_20::RASTER_WIDTH,
213            #[cfg(feature = "size_24")]
214            RasterHeight::Size24 => crate::regular::size_24::RASTER_WIDTH,
215            #[cfg(feature = "size_32")]
216            RasterHeight::Size32 => crate::regular::size_32::RASTER_WIDTH,
217        },
218        #[cfg(feature = "bold")]
219        FontWeight::Bold => match size {
220            #[cfg(feature = "size_16")]
221            RasterHeight::Size16 => crate::bold::size_16::RASTER_WIDTH,
222            #[cfg(feature = "size_20")]
223            RasterHeight::Size20 => crate::bold::size_20::RASTER_WIDTH,
224            #[cfg(feature = "size_24")]
225            RasterHeight::Size24 => crate::bold::size_24::RASTER_WIDTH,
226            #[cfg(feature = "size_32")]
227            RasterHeight::Size32 => crate::bold::size_32::RASTER_WIDTH,
228        },
229    }
230}
231
232// # THIS FILE IS AUTO GENERATED BY THE PROJECT IN "../codegen" (see repository!)