You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过read-fonts遍历字体表字段并获取其属性与值

解决字体表字段遍历的方法

你当前的代码仅遍历了字体目录中的表记录(仅包含表标签、偏移量等元信息),要获取每个表的实际字段内容,需要通过FontRef解析对应表的二进制数据,再根据不同表的结构访问其属性。以下是具体实现步骤和代码示例:

1. 导入所需的表类型

write-fonts为每个标准字体表提供了对应的结构体,按需导入常用表类型即可:

use write_fonts::read::{FontRef, tables::{Head, Hhea, Maxp, Name, Os2}};
use write_fonts::types::Tag;

2. 解析并遍历表字段

遍历表记录时,通过font.read_table(tag)获取表的二进制数据,匹配表标签解析为对应结构体后,直接访问并打印其字段属性和值:

use write_fonts::read::{FontRef, tables::{Head, Hhea, Maxp, Name, Os2}};
use write_fonts::types::Tag;

fn main() {
    let path_to_my_font_file = std::path::Path::new("/Users/ollimeier/Documents/Vary-Black.otf");
    let font_bytes = std::fs::read(path_to_my_font_file).unwrap();
    let font = FontRef::new(&font_bytes).expect("failed to read font data");

    for table_record in font.table_directory.table_records() {
        let tag = table_record.tag();
        println!("\n=== 表 {} ===", tag);
        
        // 读取表的二进制数据并解析
        match font.read_table(tag) {
            Ok(table_data) => {
                match tag {
                    Tag::HEAD => {
                        let head = Head::read(table_data).unwrap();
                        println!("版本: {:?}", head.version);
                        println!("字体修订版本: {:?}", head.font_revision);
                        println!("单位每em: {:?}", head.units_per_em);
                        println!("创建时间: {:?}", head.created);
                    }
                    Tag::HHEA => {
                        let hhea = Hhea::read(table_data).unwrap();
                        println!("上升值: {:?}", hhea.ascent);
                        println!("下降值: {:?}", hhea.descent);
                        println!("行间距: {:?}", hhea.line_gap);
                        println!("最大前进宽度: {:?}", hhea.advance_width_max);
                    }
                    Tag::MAXP => {
                        let maxp = Maxp::read(table_data).unwrap();
                        println!("字形总数: {:?}", maxp.num_glyphs);
                        println!("最大轮廓点数: {:?}", maxp.max_points);
                        println!("最大轮廓段数: {:?}", maxp.max_contours);
                    }
                    Tag::NAME => {
                        let name = Name::read(table_data).unwrap();
                        println!("名称记录数: {:?}", name.name_records.len());
                        for (idx, record) in name.name_records.iter().enumerate() {
                            println!("记录{}: 类型={}, 语言={}, 内容={:?}", 
                                idx, record.name_id, record.lang_id, record.string(&name));
                        }
                    }
                    Tag::OS_2 => {
                        let os2 = Os2::read(table_data).unwrap();
                        println!("字体权重: {:?}", os2.us_weight_class);
                        println!("字体宽度: {:?}", os2.us_width_class);
                        println!("xAvgCharWidth: {:?}", os2.x_avg_char_width);
                    }
                    _ => {
                        println!("暂未处理该表类型,原始数据长度: {} 字节", table_data.len());
                    }
                }
            }
            Err(e) => {
                println!("读取表失败: {}", e);
            }
        }
    }
}

关键说明

  • 表解析逻辑:每个标准字体表都自带read方法,传入表的二进制数据即可解析为对应结构体。
  • 字段访问:解析后的结构体包含该表的所有定义字段,直接通过点语法(如head.units_per_em)访问即可。
  • 扩展支持:如果需要处理更多表类型,只需导入对应的结构体(如Cmap、Glyf),并在match分支中添加对应解析逻辑即可。

内容的提问来源于stack exchange,提问作者Olli Meier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 19:50:06