use crate::error::{Error, ErrorKind};
use crate::fonts::GlyphIdMap;
use std::collections::HashSet;
use subsetter::{subset, GlyphRemapper};
use ttf_parser::Face;
#[derive(Debug)]
pub struct SubsetResult {
pub data: Vec<u8>,
pub glyph_id_map: GlyphIdMap,
}
pub fn subset_font(font_data: &[u8], text: &str) -> Result<Vec<u8>, Error> {
let face = Face::parse(font_data, 0).map_err(|e| {
Error::new(
format!("Failed to parse font: {:?}", e),
ErrorKind::InvalidFont,
)
})?;
let mut remapper = GlyphRemapper::new();
remapper.remap(0);
for ch in text.chars() {
if let Some(glyph_id) = face.glyph_index(ch) {
remapper.remap(glyph_id.0);
}
}
let result = subset(font_data, 0, &remapper).map_err(|e| {
Error::new(
format!("Font subsetting failed: {:?}", e),
ErrorKind::InvalidFont,
)
})?;
Ok(result)
}
pub fn subset_font_with_mapping(font_data: &[u8], text: &str) -> Result<SubsetResult, Error> {
let face = Face::parse(font_data, 0).map_err(|e| {
Error::new(
format!("Failed to parse font: {:?}", e),
ErrorKind::InvalidFont,
)
})?;
let mut remapper = GlyphRemapper::new();
remapper.remap(0);
let mut glyph_id_map = GlyphIdMap::new();
let unique_chars: HashSet<char> = text.chars().collect();
for ch in unique_chars {
if let Some(glyph_id) = face.glyph_index(ch) {
let subset_glyph_id = remapper.remap(glyph_id.0);
glyph_id_map.insert(ch, subset_glyph_id);
}
}
let data = subset(font_data, 0, &remapper).map_err(|e| {
Error::new(
format!("Font subsetting failed: {:?}", e),
ErrorKind::InvalidFont,
)
})?;
Ok(SubsetResult { data, glyph_id_map })
}
pub fn collect_used_chars(text: &str) -> HashSet<char> {
text.chars().collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_collect_used_chars() {
let text = "Hello World!";
let chars = collect_used_chars(text);
assert!(chars.contains(&'H'));
assert!(chars.contains(&'e'));
assert!(chars.contains(&' '));
assert!(chars.contains(&'!'));
assert_eq!(chars.len(), 9); }
#[test]
fn test_collect_used_chars_unicode() {
let text = "ăâîșț";
let chars = collect_used_chars(text);
assert_eq!(chars.len(), 5);
assert!(chars.contains(&'ă'));
assert!(chars.contains(&'â'));
assert!(chars.contains(&'î'));
assert!(chars.contains(&'ș'));
assert!(chars.contains(&'ț'));
}
}