#![no_std]
#![doc = include_str!("../README.md")]
pub struct Pcf<'a> {
pub glyph_byte_length: usize,
pub glyph_width: usize,
pub glyph_height: usize,
pub glyphs: &'a [u8],
pub unicode_table: Option<&'a [u8]>,
}
impl<'a> Pcf<'a> {
pub fn parse(data: &[u8]) -> Result<Pcf, ParseError> {
use ParseError::*;
if data.len() < 32 {
return Err(HeaderMissing);
}
if &data[0..4] != &[0x72, 0xb5, 0x4a, 0x86] {
return Err(InvalidMagicBytes);
}
let version = u32::from_le_bytes(data[4..8].try_into().unwrap());
if 0 != version {
return Err(UnknownVersion(version));
}
let header_size = u32::from_le_bytes(data[8..12].try_into().unwrap()) as usize;
let flags = u32::from_le_bytes(data[12..16].try_into().unwrap());
let has_unicode_table = 1 == (flags & 0x00000001);
let glyph_count = u32::from_le_bytes(data[16..20].try_into().unwrap()) as usize;
let glyph_byte_length = u32::from_le_bytes(data[20..24].try_into().unwrap()) as usize;
let glyph_height = u32::from_le_bytes(data[24..28].try_into().unwrap()) as usize;
let glyph_width = u32::from_le_bytes(data[28..32].try_into().unwrap()) as usize;
let expected_byte_count = header_size + (glyph_count * glyph_byte_length);
if data.len() < expected_byte_count {
return Err(GlyphTableTruncated { expected_byte_count: expected_byte_count });
}
let glyphs = &data[header_size..][..glyph_byte_length * glyph_count];
let unicode_table =
if has_unicode_table {
Some(&data[expected_byte_count..])
} else {
None
};
let pcf = Pcf {
glyph_byte_length: glyph_byte_length,
glyph_width: glyph_width,
glyph_height: glyph_height,
glyphs,
unicode_table,
};
Ok(pcf)
}
pub fn get_glyph_bits(&self, glyph_index: usize) -> Option<&[u8]> {
let start = self.glyph_byte_length * glyph_index;
let end = start + self.glyph_byte_length;
self.glyphs.get(start..end)
}
pub fn get_glyph_pixels<'b>(&'b self, glyph_index: usize) -> Option<impl Iterator<Item=bool> + 'b> {
let glyph_bits = self.get_glyph_bits(glyph_index)?;
let bytes_per_row = (self.glyph_width / 8) + 1;
let iterator =
(0..self.glyph_height).flat_map(move |y| {
(0..self.glyph_width).map(move |x| {
let byte_index = (x / 8) + (y * bytes_per_row);
let byte = glyph_bits[byte_index];
let bit_offset = 7 - (x % 8);
let bit = (byte >> bit_offset) & 1;
bit == 1
})
});
Some(iterator)
}
pub fn iter_unicode_entries<'b>(&'b self) -> Option<impl Iterator<Item=(usize, Result<&'b str, core::str::Utf8Error>)> + 'b> {
let table = self.unicode_table?;
let iterator = table.split(|&x| x == 0xff).enumerate().flat_map(move |(glyph_index, unicode_entries)| {
unicode_entries.split(|&x| x == 0xfe).map(move |unicode_string| {
(glyph_index, core::str::from_utf8(unicode_string))
})
});
Some(iterator)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParseError {
HeaderMissing,
InvalidMagicBytes,
UnknownVersion(u32),
GlyphTableTruncated { expected_byte_count: usize, },
}