Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 61 additions & 9 deletions bdf-parser/src/glyph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,26 @@ use std::convert::TryFrom;

use crate::{helpers::*, BoundingBox, Coord};

/// Glyph encoding
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Encoding {
/// Standard encoding
Standard(u32),
/// Non standard encoding
NonStandard(u32),
/// Unspecified encoding
#[default]
Unspecified,
}

/// Glyph.
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Glyph {
/// Name.
pub name: String,

/// Encoding.
pub encoding: Option<char>,
pub encoding: Encoding,

/// Scalable width.
pub scalable_width: Option<Coord>,
Expand Down Expand Up @@ -89,10 +101,19 @@ impl Glyph {
}
}

fn parse_encoding(input: &[u8]) -> IResult<&[u8], Option<char>> {
map(parse_to_i32, |code| {
u32::try_from(code).ok().and_then(std::char::from_u32)
})(input)
fn parse_encoding(input: &[u8]) -> IResult<&[u8], Encoding> {
let (input, standard_encoding) = parse_to_i32(input)?;
let (input, non_standard_encoding) = opt(preceded(multispace0, parse_to_i32))(input)?;

let encoding = if standard_encoding >= 0 {
Encoding::Standard(u32::try_from(standard_encoding).unwrap())
} else if let Some(non_standard) = non_standard_encoding {
Encoding::NonStandard(u32::try_from(non_standard).unwrap())
} else {
Encoding::Unspecified
};

Ok((input, encoding))
}

fn parse_bitmap(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
Expand Down Expand Up @@ -136,8 +157,11 @@ impl Glyphs {

/// Gets a glyph by the encoding.
pub fn get(&self, c: char) -> Option<&Glyph> {
// TODO: this assumes that the font uses unicode
let encoding = Encoding::Standard(c as u32);

self.glyphs
.binary_search_by_key(&Some(c), |glyph| glyph.encoding)
.binary_search_by_key(&encoding, |glyph| glyph.encoding)
.map_or(None, |i| Some(&self.glyphs[i]))
}

Expand Down Expand Up @@ -222,7 +246,7 @@ mod tests {
"#},
Glyph {
name: "ZZZZ".to_string(),
encoding: Some('A'), //65
encoding: Encoding::Standard(65), // 'A'
bitmap: vec![
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42,
0x42, 0x00, 0x00,
Expand Down Expand Up @@ -358,7 +382,35 @@ mod tests {
size: Coord::new(0, 0),
offset: Coord::new(0, 0),
},
encoding: None,
encoding: Encoding::Unspecified,
name: "000".to_string(),
scalable_width: Some(Coord::new(432, 0)),
device_width: Coord::new(6, 0),
}
);
}

#[test]
fn parse_glyph_with_no_encoding_and_index() {
let chardata = indoc! {br#"
STARTCHAR 000
ENCODING -1 123
SWIDTH 432 0
DWIDTH 6 0
BBX 0 0 0 0
BITMAP
ENDCHAR
"#};

assert_parser_ok!(
Glyph::parse(chardata),
Glyph {
bitmap: vec![],
bounding_box: BoundingBox {
size: Coord::new(0, 0),
offset: Coord::new(0, 0),
},
encoding: Encoding::NonStandard(123),
name: "000".to_string(),
scalable_width: Some(Coord::new(432, 0)),
device_width: Coord::new(6, 0),
Expand Down Expand Up @@ -386,7 +438,7 @@ mod tests {
size: Coord::new(0, 0),
offset: Coord::new(0, 0),
},
encoding: Some('\x00'),
encoding: Encoding::Standard(0),
name: "000".to_string(),
scalable_width: Some(Coord::new(432, 0)),
device_width: Coord::new(6, 0),
Expand Down
6 changes: 3 additions & 3 deletions bdf-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ mod glyph;
mod metadata;
mod properties;

pub use glyph::{Glyph, Glyphs};
pub use glyph::{Encoding, Glyph, Glyphs};
use helpers::*;
pub use metadata::Metadata;
pub use properties::{Properties, Property, PropertyError};
Expand Down Expand Up @@ -236,7 +236,7 @@ mod tests {
size: Coord::new(8, 8),
offset: Coord::new(0, 0),
},
encoding: Some('@'), //64
encoding: Encoding::Standard(64), // '@'
name: "Char 0".to_string(),
device_width: Coord::new(8, 0),
scalable_width: None,
Expand All @@ -247,7 +247,7 @@ mod tests {
size: Coord::new(8, 8),
offset: Coord::new(0, 0),
},
encoding: Some('A'), //65
encoding: Encoding::Standard(65), // 'A'
name: "Char 1".to_string(),
device_width: Coord::new(8, 0),
scalable_width: None,
Expand Down
13 changes: 10 additions & 3 deletions eg-font-converter/src/eg_bdf_font.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{fs, io, path::Path};

use anyhow::Result;
use bdf_parser::BoundingBox;
use anyhow::{bail, Result};
use bdf_parser::{BoundingBox, Encoding};
use bitvec::{prelude::*, vec::BitVec};
use eg_bdf::{BdfFont, BdfGlyph};
use embedded_graphics::{
Expand Down Expand Up @@ -44,8 +44,15 @@ impl EgBdfOutput {
for glyph in font.glyphs.iter() {
let bounding_box = bounding_box_to_rectangle(&glyph.bounding_box);

// TODO: assumes unicode
// TODO: improved error handling
let character = match glyph.encoding {
Encoding::Standard(index) => char::from_u32(index).unwrap(),
_ => bail!("invalid encoding"),
};

glyphs.push(BdfGlyph {
character: glyph.encoding.unwrap(),
character,
bounding_box,
device_width: glyph.device_width.x as u32, // TODO: check cast and handle y?
start_index: data.len(),
Expand Down
17 changes: 12 additions & 5 deletions eg-font-converter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
#![deny(unsafe_code)]

use anyhow::{anyhow, ensure, Context, Result};
use bdf_parser::{BdfFont as ParserBdfFont, Glyph, Property};
use bdf_parser::{BdfFont as ParserBdfFont, Encoding, Glyph, Property};
use embedded_graphics::mono_font::mapping::GlyphMapping;
use std::{
collections::BTreeSet,
Expand Down Expand Up @@ -292,7 +292,8 @@ impl<'a> FontConverter<'a> {
.cloned()
.map(|mut glyph| {
// replace glyph encoding for substitutes
glyph.encoding = Some(c);
// TODO: assumes unicode
glyph.encoding = Encoding::Standard(c as u32);
glyph
})
.ok_or_else(|| {
Expand Down Expand Up @@ -412,10 +413,13 @@ struct Font {

impl Font {
fn glyph_index(&self, c: char) -> Option<usize> {
// TODO: assumes unicode
let encoding = Encoding::Standard(c as u32);

self.glyphs
.iter()
.enumerate()
.find(|(_, glyph)| glyph.encoding == Some(c))
.find(|(_, glyph)| glyph.encoding == encoding)
.map(|(index, _)| index)
}

Expand All @@ -441,10 +445,13 @@ impl Font {

impl GlyphMapping for Font {
fn index(&self, c: char) -> usize {
// TODO: assumes unicode
let encoding = Encoding::Standard(c as u32);

self.glyphs
.iter()
.enumerate()
.find(|(_, glyph)| glyph.encoding.unwrap() == c)
.find(|(_, glyph)| glyph.encoding == encoding)
.map(|(index, _)| index)
.unwrap()
}
Expand Down Expand Up @@ -594,6 +601,6 @@ mod tests {
let converter = FontConverter::new_from_data(FONT, "TEST");
let font = converter.convert().unwrap();
assert_eq!(font.glyphs.len(), 1);
assert_eq!(font.glyphs[0].encoding, Some('\0'));
assert_eq!(font.glyphs[0].encoding, Encoding::Standard(0));
}
}
46 changes: 31 additions & 15 deletions eg-font-converter/src/mono_font.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{fs, io, ops::RangeInclusive, path::Path};

use anyhow::{Context, Result};
use bdf_parser::{BdfFont as ParserBdfFont, Glyph};
use anyhow::{bail, Context, Result};
use bdf_parser::{BdfFont as ParserBdfFont, Encoding, Glyph};
use eg_bdf::BdfTextStyle;
use embedded_graphics::{
image::ImageRaw,
Expand Down Expand Up @@ -75,14 +75,15 @@ impl MonoFontOutput {
let x = (i % glyphs_per_row) as i32 * character_size.width as i32;
let y = (i / glyphs_per_row) as i32 * character_size.height as i32;

Text::with_baseline(
&String::from(glyph.encoding.unwrap()),
Point::new(x, y),
style,
Baseline::Top,
)
.draw(&mut bitmap)
.unwrap();
// TODO: assumes unicode
let c = match glyph.encoding {
Encoding::Standard(index) => char::from_u32(index).unwrap(),
_ => bail!("invalid encoding"),
};

Text::with_baseline(&String::from(c), Point::new(x, y), style, Baseline::Top)
.draw(&mut bitmap)
.unwrap();
}

let data = bitmap.to_be_bytes();
Expand Down Expand Up @@ -134,8 +135,15 @@ impl MonoFontOutput {
let mime = format_ident!("{}", mapping.mime());
quote!(::embedded_graphics::mono_font::mapping::#mime)
} else {
let str_mapping =
glyphs_to_str_mapping(self.font.glyphs.iter().map(|glyph| glyph.encoding.unwrap()));
let str_mapping = glyphs_to_str_mapping(self.font.glyphs.iter().map(|glyph| {
// TODO: assumes unicode
let c = match glyph.encoding {
Encoding::Standard(index) => char::from_u32(index).unwrap(),
_ => panic!("invalid encoding"),
};

c
}));
let replacement = self.font.replacement_character;
quote!(::embedded_graphics::mono_font::mapping::StrGlyphMapping::new(#str_mapping, #replacement))
};
Expand Down Expand Up @@ -246,7 +254,15 @@ fn glyphs_to_mapping(glyphs: &[Glyph]) -> Option<Mapping> {

if glyphs
.iter()
.map(|glyph| glyph.encoding.unwrap())
.map(|glyph| {
// TODO: assumes unicode
let c = match glyph.encoding {
Encoding::Standard(index) => char::from_u32(index).unwrap(),
_ => panic!("invalid encoding"),
};

c
})
.eq(chars.iter().copied())
{
return Some(mapping);
Expand Down Expand Up @@ -293,7 +309,7 @@ mod tests {
fn test_glyphs_to_mapping() {
let glyphs = (' '..='\x7F')
.map(|c| Glyph {
encoding: Some(c),
encoding: Encoding::Standard(c as u32),
..Glyph::default()
})
.collect::<Vec<_>>();
Expand All @@ -302,7 +318,7 @@ mod tests {
let glyphs = (' '..='\x7F')
.chain(0xA0 as char..=0xFF as char)
.map(|c| Glyph {
encoding: Some(c),
encoding: Encoding::Standard(c as u32),
..Glyph::default()
})
.collect::<Vec<_>>();
Expand Down
Loading