add maxp table decoding
This commit is contained in:
parent
db07f3772b
commit
a11df167de
23
src/font.rs
23
src/font.rs
|
@ -1,5 +1,6 @@
|
|||
mod table_directory;
|
||||
mod character_map;
|
||||
mod maximum_profile;
|
||||
mod search;
|
||||
|
||||
use std::{fs::File, io::{BufReader, Read}};
|
||||
|
@ -7,6 +8,7 @@ use std::{fs::File, io::{BufReader, Read}};
|
|||
use bincode::Options;
|
||||
use character_map::CharacterMap;
|
||||
use log::{debug, info};
|
||||
use maximum_profile::MaximumProfile;
|
||||
use table_directory::TableDirectory;
|
||||
|
||||
fn deserialize<R: Read, T: serde::de::DeserializeOwned>(reader: R) -> bincode::Result<T> {
|
||||
|
@ -15,9 +17,9 @@ fn deserialize<R: Read, T: serde::de::DeserializeOwned>(reader: R) -> bincode::R
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Font {
|
||||
data_source: BufReader<File>,
|
||||
table_directory: TableDirectory,
|
||||
character_map: CharacterMap
|
||||
character_map: CharacterMap,
|
||||
maximum_profile: MaximumProfile
|
||||
}
|
||||
|
||||
impl Font {
|
||||
|
@ -25,25 +27,20 @@ impl Font {
|
|||
let mut buf_reader = BufReader::new(file.try_clone()?);
|
||||
let table_directory = TableDirectory::new(&mut buf_reader)?;
|
||||
|
||||
let Some(cmap) = table_directory.get_table("cmap") else {
|
||||
return Err(Box::new(bincode::ErrorKind::Custom("Missing table 'cmap'".into())));
|
||||
};
|
||||
|
||||
let character_map = CharacterMap::new(file.try_clone()?, cmap)?;
|
||||
let character_map = table_directory.get_table(&file)?;
|
||||
debug!("{character_map:#?}");
|
||||
|
||||
let maximum_profile = table_directory.get_table(&file)?;
|
||||
debug!("{maximum_profile:#?}");
|
||||
|
||||
Ok(Font {
|
||||
data_source: buf_reader,
|
||||
table_directory,
|
||||
character_map
|
||||
character_map,
|
||||
maximum_profile
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_data_for(&mut self, glyph: char) -> Result<(), &'static str> {
|
||||
let Some(table) = self.table_directory.get_table("glyf") else {
|
||||
return Err("Failed to get table. It doesn't exist");
|
||||
};
|
||||
|
||||
let Some(glyph_id) = self.character_map.get_char(glyph) else {
|
||||
return Err("Failed to get glyph id for char");
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ use bincode::{ErrorKind, Result};
|
|||
use log::{debug, error, warn};
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
|
||||
use super::{deserialize, table_directory::TableDirectoryRecord, search::SearchParameters};
|
||||
use super::{deserialize, search::SearchParameters, table_directory::{FontTable, TableDirectoryRecord}};
|
||||
|
||||
#[derive(Debug, Deserialize, Copy, Clone)]
|
||||
struct SegmentToDeltaHeader {
|
||||
|
@ -37,19 +37,21 @@ impl SegmentToDelta {
|
|||
Ok(values)
|
||||
}
|
||||
|
||||
fn new<R: Read + Seek>(reader: &mut R, file: File) -> Result<SegmentToDelta> {
|
||||
fn new(mut reader: BufReader<File>) -> Result<SegmentToDelta> {
|
||||
let header: SegmentToDeltaHeader = deserialize(reader.by_ref())?;
|
||||
let search_params: SearchParameters = deserialize(reader.by_ref())?;
|
||||
|
||||
let end_code = Self::get_next_vec(reader, search_params.seg_count_x2 >> 1)?;
|
||||
let end_code = Self::get_next_vec(&mut reader, search_params.seg_count_x2 >> 1)?;
|
||||
reader.seek_relative(2)?;
|
||||
let start_code = Self::get_next_vec(reader, search_params.seg_count_x2 >> 1)?;
|
||||
let id_delta = Self::get_next_vec(reader, search_params.seg_count_x2 >> 1)?;
|
||||
let id_range_offset = Self::get_next_vec(reader, search_params.seg_count_x2 >> 1)?;
|
||||
let start_code = Self::get_next_vec(&mut reader, search_params.seg_count_x2 >> 1)?;
|
||||
let id_delta = Self::get_next_vec(&mut reader, search_params.seg_count_x2 >> 1)?;
|
||||
let id_range_offset = Self::get_next_vec(&mut reader, search_params.seg_count_x2 >> 1)?;
|
||||
|
||||
let glyph_table_pos = reader.stream_position()? as u32;
|
||||
|
||||
Ok(SegmentToDelta {
|
||||
data_source: BufReader::new(file),
|
||||
glyph_table: reader.stream_position()? as u32,
|
||||
data_source: reader,
|
||||
glyph_table: glyph_table_pos,
|
||||
header,
|
||||
search_params,
|
||||
end_code,
|
||||
|
@ -119,33 +121,6 @@ impl CharacterMap {
|
|||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn new(file: File, cmap: TableDirectoryRecord) -> Result<CharacterMap> {
|
||||
let mut reader = BufReader::new(file.try_clone()?);
|
||||
reader.seek(SeekFrom::Start(cmap.offset as u64))?;
|
||||
|
||||
reader.seek_relative(2)?; // Skip version because i dont care
|
||||
let num_tables: u16 = deserialize(reader.by_ref())?;
|
||||
|
||||
let Some(table) = Self::find_unicode_table(&mut reader, num_tables) else {
|
||||
return Err(Box::new(ErrorKind::Custom("No encoding for Unicode 2.0 BMP".into())));
|
||||
};
|
||||
|
||||
reader.seek(SeekFrom::Start((cmap.offset + table.offset) as u64))?;
|
||||
let format: u16 = deserialize(reader.by_ref())?;
|
||||
|
||||
if format != 4 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
Ok(CharacterMap {
|
||||
mapping_table: SegmentToDelta::new(reader.by_ref(), file)?,
|
||||
|
||||
_table_start: cmap.offset,
|
||||
_length: cmap.length,
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_char(&mut self, c: char) -> Option<u16> {
|
||||
let code = c as u32;
|
||||
|
@ -159,3 +134,33 @@ impl CharacterMap {
|
|||
return self.mapping_table.get_glyph_id(code);
|
||||
}
|
||||
}
|
||||
|
||||
impl FontTable for CharacterMap {
|
||||
const TAG: &'static str = "cmap";
|
||||
|
||||
fn decode(mut reader: BufReader<File>, table: &TableDirectoryRecord) -> Result<Self>
|
||||
where Self: Sized
|
||||
{
|
||||
reader.seek_relative(2)?; // Skip version because i dont care
|
||||
let num_tables: u16 = deserialize(reader.by_ref())?;
|
||||
|
||||
let Some(record) = Self::find_unicode_table(&mut reader, num_tables) else {
|
||||
return Err(Box::new(ErrorKind::Custom("No encoding for Unicode 2.0 BMP".into())));
|
||||
};
|
||||
|
||||
reader.seek(SeekFrom::Start((table.offset + record.offset) as u64))?;
|
||||
let format: u16 = deserialize(reader.by_ref())?;
|
||||
|
||||
if format != 4 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
Ok(CharacterMap {
|
||||
mapping_table: SegmentToDelta::new(reader)?,
|
||||
|
||||
_table_start: table.offset,
|
||||
_length: table.length,
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
54
src/font/maximum_profile.rs
Normal file
54
src/font/maximum_profile.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use std::{fs::File, io::{BufReader, Read, Seek, SeekFrom}};
|
||||
|
||||
use bincode::{de::read, Result};
|
||||
use log::debug;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::{deserialize, table_directory::{FontTable, TableDirectoryRecord}};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct MaximumProfileV05 {
|
||||
num_glyphs: u16
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct MaximumProfileV10 {
|
||||
num_glyphs: u16,
|
||||
max_points: u16,
|
||||
max_countours: u16,
|
||||
max_composite_points: u16,
|
||||
max_composite_countours: u16,
|
||||
max_zones: u16,
|
||||
max_twilight_points: u16,
|
||||
max_storage: u16,
|
||||
max_function_defs: u16,
|
||||
max_instruction_defs: u16,
|
||||
max_stack_elements: u16,
|
||||
max_size_of_instructions: u16,
|
||||
max_component_elements: u16,
|
||||
max_component_depth: u16
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MaximumProfile {
|
||||
V0_5(MaximumProfileV05),
|
||||
V1_0(MaximumProfileV10)
|
||||
}
|
||||
|
||||
impl FontTable for MaximumProfile {
|
||||
const TAG: &'static str = "maxp";
|
||||
|
||||
fn decode(mut reader: BufReader<File>, _: &TableDirectoryRecord) -> Result<Self>
|
||||
where Self: Sized
|
||||
{
|
||||
let version: u32 = deserialize(reader.by_ref())?;
|
||||
debug!("maxp table version: {:#08x}", version);
|
||||
|
||||
match version {
|
||||
0x00005000 => todo!(),
|
||||
0x00010000 => Ok(MaximumProfile::V1_0(deserialize(reader.by_ref())?)),
|
||||
_ => { return Err(bincode::ErrorKind::Custom("Invalid maxp table version".into()).into()); }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::HashMap, io::{Read, Seek}};
|
||||
use std::{collections::HashMap, fs::File, io::{BufReader, Read, Seek, SeekFrom}};
|
||||
|
||||
use bincode::Result;
|
||||
use serde::Deserialize;
|
||||
|
@ -37,12 +37,29 @@ impl TableDirectory {
|
|||
Ok(TableDirectory(tables))
|
||||
}
|
||||
|
||||
pub fn get_table(&self, table: &str) -> Option<TableDirectoryRecord> {
|
||||
let table_id = table.as_bytes().first_chunk::<4>().unwrap().iter().fold(0u32, |running, &val| {
|
||||
pub fn get_table<T: FontTable>(&self, file: &File) -> Result<T> {
|
||||
let table_id = T::TAG.as_bytes().first_chunk::<4>().unwrap().iter().fold(0u32, |running, &val| {
|
||||
(running << 8) | (val as u32)
|
||||
});
|
||||
|
||||
self.0.get(&table_id).copied()
|
||||
T::find_and_decode(file, self.0.get(&table_id).ok_or(bincode::ErrorKind::Custom(format!("No table with id '{}' found", T::TAG)))?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub trait FontTable {
|
||||
const TAG: &'static str;
|
||||
|
||||
fn decode(reader: BufReader<File>, table: &TableDirectoryRecord) -> Result<Self>
|
||||
where Self: Sized;
|
||||
|
||||
fn find_and_decode(file: &File, table: &TableDirectoryRecord) -> Result<Self>
|
||||
where Self: Sized
|
||||
{
|
||||
let file = file.try_clone()?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
reader.seek(SeekFrom::Start(table.offset as u64))?;
|
||||
Self::decode(reader, table)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue