ttf_parser/tables/
sbix.rsuse core::convert::TryFrom;
use core::num::NonZeroU16;
use crate::{GlyphId, RasterGlyphImage, RasterImageFormat, Tag};
use crate::parser::{Stream, FromData, Offset, Offset32};
pub fn parse(
data: &[u8],
number_of_glyphs: NonZeroU16,
glyph_id: GlyphId,
pixels_per_em: u16,
depth: u8,
) -> Option<RasterGlyphImage> {
if depth == 10 {
return None;
}
let total_glyphs = u32::from(number_of_glyphs.get().checked_add(1)?);
let mut s = Stream::new(data);
let version: u16 = s.read()?;
if version != 1 {
return None;
}
s.skip::<u16>(); let count: u32 = s.read()?;
if count == 0 {
return None;
}
let strikes = s.read_array32::<Offset32>(count)?;
let mut idx = 0;
let mut max_ppem = 0;
{
for (i, offset) in strikes.into_iter().enumerate() {
let mut s = Stream::new_at(data, offset.to_usize())?;
let ppem: u16 = s.read()?;
s.skip::<u16>(); if (pixels_per_em <= ppem && ppem < max_ppem) ||
(pixels_per_em > max_ppem && ppem > max_ppem)
{
idx = i as u32;
max_ppem = ppem;
}
}
}
let offset = strikes.get(idx)?;
let mut s = Stream::new_at(data, offset.to_usize())?;
s.skip::<u16>(); s.skip::<u16>(); let glyph_offsets = s.read_array32::<Offset32>(total_glyphs)?;
let start = glyph_offsets.get(u32::from(glyph_id.0))?.to_usize();
let end = glyph_offsets.get(u32::from(glyph_id.0.checked_add(1)?))?.to_usize();
if start == end {
return None;
}
let data_len = end.checked_sub(start)?.checked_sub(8)?; let mut s = Stream::new_at(data, offset.to_usize() + start)?;
let x: i16 = s.read()?;
let y: i16 = s.read()?;
let image_type: Tag = s.read()?;
let image_data = s.read_bytes(data_len)?;
let format = match &image_type.to_bytes() {
b"png " => RasterImageFormat::PNG,
b"dupe" => {
let glyph_id = GlyphId::parse(image_data)?;
return parse(data, number_of_glyphs, glyph_id, pixels_per_em, depth + 1);
}
_ => {
return None;
}
};
let (width, height) = png_size(image_data)?;
Some(RasterGlyphImage {
x,
y,
width,
height,
pixels_per_em: max_ppem,
format,
data: image_data,
})
}
fn png_size(data: &[u8]) -> Option<(u16, u16)> {
let mut s = Stream::new_at(data, 16)?;
let width: u32 = s.read()?;
let height: u32 = s.read()?;
Some((
u16::try_from(width).ok()?,
u16::try_from(height).ok()?,
))
}