1#![cfg_attr(not(test), no_std)]
73#![warn(rust_2018_idioms)]
74
75use core::num::NonZeroU8;
76use embedded_graphics::{
77 draw_target::DrawTarget,
78 geometry::{Dimensions, OriginDimensions, Point, Size},
79 image::{ImageDrawable, ImageRaw},
80 mono_font::mapping::GlyphMapping,
81 pixelcolor::BinaryColor,
82 primitives::Rectangle,
83 text::{
84 renderer::{TextMetrics, TextRenderer},
85 Baseline,
86 },
87 Pixel,
88};
89
90#[cfg(feature = "artwiz")]
92pub mod artwiz;
93
94#[cfg(feature = "bitocra")]
95pub mod bitocra;
96
97#[cfg(feature = "cherry")]
98pub mod cherry;
99
100#[cfg(feature = "creep")]
101pub mod creep;
102
103#[cfg(feature = "ctrld")]
104pub mod ctrld;
105
106#[cfg(feature = "dina")]
107pub mod dina;
108
109#[cfg(feature = "dylex")]
110pub mod dylex;
111
112#[cfg(feature = "envypn")]
113pub mod envypn;
114
115#[cfg(feature = "gohufont")]
116pub mod gohufont;
117
118#[cfg(feature = "gomme")]
119pub mod gomme;
120
121#[cfg(feature = "haxor")]
122pub mod haxor;
123
124#[cfg(feature = "jmk")]
125pub mod jmk;
126
127#[cfg(feature = "kakwa")]
128pub mod kakwa;
129
130#[cfg(feature = "knxt")]
131pub mod knxt;
132
133#[cfg(feature = "lokaltog")]
134pub mod lokaltog;
135
136#[cfg(feature = "mplus")]
137pub mod mplus;
138
139#[cfg(feature = "orp")]
140pub mod orp;
141
142#[cfg(feature = "peep")]
143pub mod peep;
144
145#[cfg(feature = "phallus")]
146pub mod phallus;
147
148#[cfg(feature = "progsole")]
149pub mod progsole;
150
151#[cfg(feature = "scientifica")]
152pub mod scientifica;
153
154#[cfg(feature = "spleen")]
155pub mod spleen;
156
157#[cfg(feature = "tamzen")]
158pub mod tamzen;
159
160#[cfg(feature = "terminus")]
161pub mod terminus;
162
163#[cfg(feature = "tewi")]
164pub mod tewi;
165
166#[cfg(feature = "trisk")]
167pub mod trisk;
168
169#[cfg(feature = "xbmicons")]
170pub mod xbmicons;
171
172const ONE: NonZeroU8 = match NonZeroU8::new(1) {
174 Some(one) => one,
175 None => unreachable!(),
176};
177
178#[derive(Clone, Copy)]
206pub struct BitmapFont<'a> {
207 pub bitmap: ImageRaw<'a, BinaryColor>,
209
210 pub glyph_mapping: &'a dyn GlyphMapping,
212
213 pub size: Size,
215
216 pub pixels: NonZeroU8,
218}
219
220impl<'a> BitmapFont<'a> {
221 #[inline]
225 pub const fn new(
226 bitmap: ImageRaw<'a, BinaryColor>,
227 glyph_mapping: &'a dyn GlyphMapping,
228 width: u32,
229 height: u32,
230 ) -> Self {
231 Self {
232 bitmap,
233 glyph_mapping,
234 size: Size::new(width, height),
235 pixels: ONE,
236 }
237 }
238
239 #[inline]
241 pub const fn width(&self) -> u32 {
242 self.size.width * self.pixels.get() as u32
243 }
244
245 #[inline]
247 pub const fn height(&self) -> u32 {
248 self.size.height * self.pixels.get() as u32
249 }
250
251 #[inline]
253 pub const fn base_width(&self) -> u32 {
254 self.size.width
255 }
256
257 #[inline]
259 pub const fn base_height(&self) -> u32 {
260 self.size.height
261 }
262
263 #[inline]
265 pub const fn pixel_multiplier(&self) -> u8 {
266 self.pixels.get()
267 }
268
269 pub fn draw_glyph<D>(
271 &self,
272 idx: u32,
273 target: &mut D,
274 color: BinaryColor,
275 pos: Point,
276 ) -> Result<(), D::Error>
277 where
278 D: DrawTarget<Color = BinaryColor>,
279 {
280 let bitmap_size = self.bitmap.size();
281 let chars_per_row = bitmap_size.width / self.size.width;
282 let row = idx / chars_per_row;
283
284 let char_x = (idx - (row * chars_per_row)) * self.size.width;
286 let char_y = row * self.size.height;
287 let area = Rectangle::new(Point::new(char_x as _, char_y as _), self.size);
288
289 let mut pixel_target = PixelMultiplyDrawTarget {
291 target,
292 color,
293 offset: pos,
294 pixels: self.pixels,
295 };
296 self.bitmap.draw_sub_image(&mut pixel_target, &area)?;
297
298 Ok(())
299 }
300
301 #[must_use]
320 pub const fn pixel_double(self) -> Self {
321 self.pixel_multiply(2)
322 }
323
324 #[must_use]
328 pub const fn pixel_triple(self) -> Self {
329 self.pixel_multiply(3)
330 }
331
332 #[must_use]
338 pub const fn pixel_multiply(mut self, multiplier: u8) -> Self {
339 let new_multiplier = self.pixels.get() * multiplier;
341 self.pixels = match NonZeroU8::new(new_multiplier) {
342 Some(px) => px,
343 None => panic!("pixel multiplier cannot be zero"),
344 };
345 self
346 }
347}
348
349#[derive(Clone, Copy)]
380#[non_exhaustive]
381pub struct TextStyle<'a> {
382 pub font: &'a BitmapFont<'a>,
384 pub color: BinaryColor,
386}
387
388impl<'a> TextStyle<'a> {
389 #[inline]
391 pub const fn new(font: &'a BitmapFont<'a>, color: BinaryColor) -> Self {
392 Self { font, color }
393 }
394}
395
396impl TextRenderer for TextStyle<'_> {
397 type Color = BinaryColor;
398
399 fn draw_string<D>(
400 &self,
401 text: &str,
402 mut pos: Point,
403 _baseline: Baseline,
404 target: &mut D,
405 ) -> Result<Point, D::Error>
406 where
407 D: DrawTarget<Color = Self::Color>,
408 {
409 for c in text.chars() {
410 let glyph_idx = self.font.glyph_mapping.index(c) as u32;
411 self.font.draw_glyph(glyph_idx, target, self.color, pos)?;
412 pos += Size::new(self.font.width(), 0);
413 }
414 Ok(pos)
415 }
416
417 fn draw_whitespace<D>(
418 &self,
419 width: u32,
420 pos: Point,
421 _baseline: Baseline,
422 _target: &mut D,
423 ) -> Result<Point, D::Error>
424 where
425 D: DrawTarget<Color = Self::Color>,
426 {
427 Ok(pos + Size::new(width * self.font.width(), 0))
429 }
430
431 fn measure_string(&self, text: &str, pos: Point, _baseline: Baseline) -> TextMetrics {
432 let width = self.font.width() * text.len() as u32;
433 let height = self.font.height();
434 TextMetrics {
435 bounding_box: Rectangle::new(pos, Size::new(width, height)),
436 next_position: pos + Size::new(width, 0),
437 }
438 }
439
440 fn line_height(&self) -> u32 {
441 self.font.height()
442 }
443}
444
445struct PixelMultiplyDrawTarget<'a, D: DrawTarget<Color = BinaryColor>> {
450 target: &'a mut D,
451 color: BinaryColor,
452 offset: Point,
453 pixels: NonZeroU8,
454}
455
456impl<D> Dimensions for PixelMultiplyDrawTarget<'_, D>
457where
458 D: DrawTarget<Color = BinaryColor>,
459{
460 fn bounding_box(&self) -> Rectangle {
461 let mut bb = self.target.bounding_box();
462 bb.top_left -= self.offset;
463 bb.top_left /= self.pixels.get().into();
464 bb.size /= self.pixels.get().into();
465 bb
466 }
467}
468
469impl<D> DrawTarget for PixelMultiplyDrawTarget<'_, D>
470where
471 D: DrawTarget<Color = BinaryColor>,
472{
473 type Color = BinaryColor;
474 type Error = D::Error;
475
476 fn draw_iter<I>(&mut self, pixel_iter: I) -> Result<(), Self::Error>
477 where
478 I: IntoIterator<Item = Pixel<BinaryColor>>,
479 {
480 let color = self.color;
481 let offset = self.offset;
482 let multiplier = self.pixels.get();
483
484 self.target.draw_iter(
485 pixel_iter
486 .into_iter()
487 .filter(|pixel| pixel.1 == BinaryColor::On)
488 .flat_map(|pixel| {
489 PixelMultiplyIterator::new(pixel, multiplier)
490 .map(move |p| Pixel(p.0 + offset, color))
491 }),
492 )
493 }
494}
495
496struct PixelMultiplyIterator {
498 color: BinaryColor,
499 base_pos: Point,
500 x: u8,
501 y: u8,
502 multiplier: u8,
503}
504
505impl PixelMultiplyIterator {
506 fn new(pixel: Pixel<BinaryColor>, multiplier: u8) -> Self {
507 Self {
508 color: pixel.1,
509 base_pos: pixel.0 * multiplier as i32,
510 x: 0,
511 y: 0,
512 multiplier,
513 }
514 }
515}
516
517impl Iterator for PixelMultiplyIterator {
518 type Item = Pixel<BinaryColor>;
519
520 fn next(&mut self) -> Option<Pixel<BinaryColor>> {
521 if self.y >= self.multiplier {
522 return None;
523 }
524
525 let pixel = Pixel(
526 Point::new(
527 self.base_pos.x + self.x as i32,
528 self.base_pos.y + self.y as i32,
529 ),
530 self.color,
531 );
532
533 self.x += 1;
534 if self.x >= self.multiplier {
535 self.x = 0;
536 self.y += 1;
537 }
538
539 Some(pixel)
540 }
541
542 fn size_hint(&self) -> (usize, Option<usize>) {
543 let remaining =
544 (self.multiplier - self.y) as usize * self.multiplier as usize - self.x as usize;
545 (remaining, Some(remaining))
546 }
547}
548
549impl ExactSizeIterator for PixelMultiplyIterator {}
550
551#[cfg(test)]
552mod tests {
553 use super::*;
554
555 fn px(x: i32, y: i32) -> Pixel<BinaryColor> {
556 Pixel(Point::new(x, y), BinaryColor::On)
557 }
558
559 #[test]
560 fn pixel_multiply_iterator_1x() {
561 let pixels: Vec<_> = PixelMultiplyIterator::new(px(0, 0), 1).collect();
562 assert_eq!(pixels, vec![px(0, 0)]);
563
564 let pixels: Vec<_> = PixelMultiplyIterator::new(px(5, 3), 1).collect();
565 assert_eq!(pixels, vec![px(5, 3)]);
566 }
567
568 #[test]
569 fn pixel_multiply_iterator_2x() {
570 let pixels: Vec<_> = PixelMultiplyIterator::new(px(0, 0), 2).collect();
571 assert_eq!(pixels, vec![px(0, 0), px(1, 0), px(0, 1), px(1, 1)]);
572
573 let pixels: Vec<_> = PixelMultiplyIterator::new(px(1, 2), 2).collect();
574 assert_eq!(pixels, vec![px(2, 4), px(3, 4), px(2, 5), px(3, 5)]);
575 }
576
577 #[test]
578 fn pixel_multiply_iterator_3x() {
579 let pixels: Vec<_> = PixelMultiplyIterator::new(px(0, 0), 3).collect();
580 assert_eq!(
581 pixels,
582 vec![
583 px(0, 0),
584 px(1, 0),
585 px(2, 0),
586 px(0, 1),
587 px(1, 1),
588 px(2, 1),
589 px(0, 2),
590 px(1, 2),
591 px(2, 2)
592 ]
593 );
594 }
595
596 #[test]
597 fn pixel_multiply_iterator_exact_size() {
598 let iter = PixelMultiplyIterator::new(px(0, 0), 3);
599 assert_eq!(iter.len(), 9);
600
601 let mut iter = PixelMultiplyIterator::new(px(0, 0), 2);
602 assert_eq!(iter.len(), 4);
603 iter.next();
604 assert_eq!(iter.len(), 3);
605 iter.next();
606 assert_eq!(iter.len(), 2);
607 }
608}