fontTools 中 `bloc`(Bitmap Location)表解析:与 `bdat` 配套的 AAT 位图定位表
开发工具【免费下载链接】fonttoolsA library to manipulate font files from Python.项目地址https://gitcode.com/gh_mirrors/fo/fonttools点击查看免费下载bloc是 Apple Advanced TypographyAAT字体规范中的位图定位表Bitmap Location table在 fontTools 中由 Lib/fontTools/ttLib/tables/_b_l_o_c.py 实现。它的二进制结构与 OpenType 的EBLC表完全一致并与存放位图像素数据的bdat表配对使用。读完本文你将掌握bloc与bdat的配对关系、它复用的EBLC实现细节strike 结构、五种 indexSubTable 格式、sbit 行度量以及如何通过 ttx 在 XML 与二进制之间读写这些位图表。一、bloc是什么AAT 体系中的位图定位表在 Apple 的 AATApple Advanced Typography字体体系中内嵌位图embedded bitmap由两张表共同承担blocBitmap Location记录位图数据存放的位置信息包括每个像素尺寸档位strike的度量、位深以及每个字形位图在bdat中的数据区间bdatBitmap Data实际存放单色或灰度位图像素数据。这两张表在 fontTools 中的对应实现分别为Lib/fontTools/ttLib/tables/_b_l_o_c.py ——table__b_l_o_cLib/fontTools/ttLib/tables/_b_d_a_t.py ——table__b_d_a_t。从源码看bloc的实现极其精简——它直接继承自EBLC表类只重写了依赖关系from fontTools.ttLib.tables.E_B_L_C_ import table_E_B_L_C_ class table__b_l_o_c(table_E_B_L_C_): dependencies [bdat]而bdat同样继承自EBDT表类并指定locatorName blocfrom fontTools.ttLib.tables.E_B_D_T_ import table_E_B_D_T_ class table__b_d_a_t(table_E_B_D_T_): locatorName bloc这两段代码构成了一组关键约定bloc的dependencies [bdat]dependencies是 fontTools 中表依赖机制的字段用于在保存或重排表顺序时确保bdat先于bloc处理因为bloc编译时需要读取bdat中的位图数据位置来生成偏移信息。bdat的locatorName bloclocatorName告诉EBDT的实现代码到哪里去找定位表ttFont[locatorName]即bdat解压decompile和编译compile时都会通过bloc的strikes与indexSubTables来定位每个字形的数据区间。与之对照标准 OpenType 体系中EBLC表类的locatorName是EBLCEBDT表类的依赖是[EBDT]见 E_B_L_C_.py 与 E_B_D_T_.py。也就是说AAT 的bloc/bdat与 OpenType 的EBLC/EBDT是结构同构的姊妹对bloc≡EBLCbdat≡EBDT。fontTools 正是通过继承 重写依赖关系这一设计用一套代码同时支撑了两套规范的表。二、bloc的二进制结构与EBLC完全一致bloc的二进制布局定义在 E_B_L_C_.py 中使用 fontTools 的sstruct结构化字符串格式描述全部字段为大端序big endian表头eblcHeaderFormat8 字节字段类型含义version16.16F版本号固定 16.16 定点数numSizesIstrike位图尺寸档位数量每个 strike 的bitmapSizeTable分三段共 36 字节 2 个 12 字节度量块第一部分16 字节indexSubTableArrayOffsetI本 strike 的索引子表数组偏移、indexTablesSizeI索引区域总大小、numberOfIndexSubTablesI索引子表数量、colorRefI颜色引用中间为hori与vert两组sbitLineMetrics各 12 字节字段依次为ascenderb、descenderb、widthMaxB、caretSlopeNumeratorb、caretSlopeDenominatorb、caretOffsetb、minOriginSBb、minAdvanceSBb、maxBeforeBLb、minAfterBLb、pad1b、pad2b第二部分8 字节startGlyphIndexH、endGlyphIndexH、ppemXB、ppemYB、bitDepthB、flagsb。索引子表数组indexSubTableArrayFormat HHL8 字节/条每个条目为firstGlyphIndexH、lastGlyphIndexH、additionalOffsetToIndexSubtableL指向本条目对应索引子表的偏移。索引子表头indexSubHeaderFormat HHL8 字节indexFormatH索引子表格式 1~5、imageFormatH图像格式、imageDataOffsetL图像数据偏移。其中每个字段的字节序、长度均与 OpenType 规范中EBLC一致因此任何能处理EBLC的解析器可以直接套用于bloc。三、五种 indexSubTable 格式indexFormat 1~5bloc的核心解析逻辑集中在EblcIndexSubTable及其子类。table_E_B_L_C_提供了可扩展的工厂方法getIndexFormatClass(indexFormat)按格式号返回对应类格式号到类的映射为eblc_sub_table_classes {1: ..., 2: ..., 3: ..., 4: ..., 5: ...}见 E_B_L_C_.py。五种格式的特性从源码可以归纳如下格式类特点1eblc_index_sub_table_1偏移数组每个偏移为 32 位L可含跳过字形skip glyphs2eblc_index_sub_table_2定长数据先记录imageSizeL与BigGlyphMetrics字形 ID 必须连续3eblc_index_sub_table_3偏移数组每个偏移为 16 位H同样可含跳过字形4eblc_index_sub_table_4glyphCode-offset 成对数组HH允许任意字形顺序5eblc_index_sub_table_5定长数据 显式 glyph ID 列表H支持跨 strike 复用同一图像数据格式 1 与 3偏移数组族由_createOffsetArrayIndexSubTableMixin闭包生成的OffsetArrayIndexSubTableMixin统一实现见 E_B_L_C_.py二者差异仅在偏移值的数据类型32 位 vs 16 位。解压时该 Mixin 依据firstGlyphIndex到lastGlyphIndex的连续字形区间切出偏移数组将每个偏移加上imageDataOffset得到实际位置并把起始字节等于结束字节即零大小的条目视为跳过字形通过removeSkipGlyphs()过滤见 E_B_L_C_.py编译时则反向插入零大小条目补齐字形区间并要求数据连续curLoc[1] nxtLoc[0]断言最后将imageDataOffset重置为最小偏移从而允许 XML 往返时不保存该字段。格式 2定长数据ID 连续在eblc_index_sub_table_2中实现见 E_B_L_C_.py数据区以 4 字节imageSize开头随后是BigGlyphMetrics每个字形位图按固定imageSize顺序排列。编译断言字形 ID 必须严格连续glyphIds list(range(...))否则报错Format 2 ids must be consecutive.。其数据补齐行为由FixedSizeIndexSubTableMixin.padBitmapData完成若实际数据短于imageSize则补零若超长则断言失败。格式 4glyphCode-offset 对在eblc_index_sub_table_4中实现见 E_B_L_C_.py数据区先写 4 字节numGlyphs随后是numGlyphs 1个codeOffsetPairHH每个对包含字形码与相对偏移最后一个对仅用于提供区间终点。它允许字形 ID 以任意顺序出现编译时同样要求数据区间连续。格式 5定长数据 显式 ID 列表在eblc_index_sub_table_5中实现见 E_B_L_C_.py依次存放imageSize、BigGlyphMetrics、numGlyphsL与字形 ID 数组H奇数个时补齐一个 0。由于 ID 是显式列出的同一份定长数据可以被多个 strike 或索引子表引用——EBDT编译时正是利用这一点通过id(glyph)对象去重让被多处引用的字形只写一次数据见 E_B_D_T_.py。四、strike 模型与水平/垂直行度量bloc的解析结果以self.strikes列表呈现每个元素是Strike对象包含bitmapSizeTableBitmapSizeTable类型与indexSubTablesEblcIndexSubTable列表。Strike、BitmapSizeTable、SbitLineMetrics三个辅助类都在 E_B_L_C_.py 中定义。BitmapSizeTable中hori与vert两个方向各有一组SbitLineMetrics字段与二进制布局一一对应。它的 XML 导出会跳过前三个字节偏移/计数类字段indexSubTableArrayOffset、indexTablesSize、numberOfIndexSubTables因为这些值在编译时会重新计算其余度量字段如ppemX、ppemY、bitDepth、startGlyphIndex等则逐个写成name value.../标签。SbitLineMetrics的 XML 格式为带direction属性的sbitLineMetrics元素sbitLineMetrics directionhori ascender value12/ descender value-3/ widthMax value10/ !-- caretSlopeNumerator / caretSlopeDenominator / caretOffset minOriginSB / minAdvanceSB / maxBeforeBL / minAfterBL / pad1 / pad2 -- /sbitLineMetricsBitmapGlyphMetrics中还定义了两种字形度量结构见 BitmapGlyphMetrics.pyBigGlyphMetricsheight/width/horiBearingX/horiBearingY/horiAdvance/vertBearingX/vertBearingY/vertAdvance共 9 字节与SmallGlyphMetricsheight/width/BearingX/BearingY/Advance共 5 字节二者被EBLC的格式 2/5 与EBDT的位图格式共同复用。五、bloc与bdat的协作解压与编译流程bdat继承EBDT的解压/编译都需要bloc的配合这是理解这对表的关键解压decompileEBDT.decompile先读取自己的版本头然后通过locator ttFont[self.__class__.locatorName]取得bloc表遍历locator.strikes中每个 strike 的每个indexSubTable取出indexSubTable.names字形名与indexSubTable.locations数据区间(startByte, endByte)按区间从bdat数据中切片出每个字形的位图。相同的区间会被去重复用glyphDict缓存避免重复解码同一份数据见 E_B_D_T_.py。编译compileEBDT.compile同样以bloc的 strikes/indexSubTables 为骨架为每个字形编译位图数据、按imageFormat对应的类打包调用curIndexSubTable.padBitmapData(data)处理定长格式的补零记录(startByte, endByte)区间回写到curIndexSubTable.locations随后bloc的编译流程根据这些 locations 重新计算所有偏移见 E_B_D_T_.py。bloc自身的编译EBLC.compile按表头 → 各 bitmapSizeTable → 交替排列的 indexSubTableArray 与 indexSubTable的顺序重建整张表。源码注释明确指出见 E_B_L_C_.py所有字节偏移与大小信息在导出 XML 时都会丢失因此编译时必须全部重新计算而numberOfIndexSubTables等计数信息则通过断言校验。firstGlyphIndex/lastGlyphIndex由min/max从字形 ID 重新推导imageDataOffset会重置为区间最小偏移以支持安全的 XML 往返round-trip。另外值得一提的是EblcIndexSubTable与BitmapGlyph都实现了惰性解压lazy decompile构造函数只保存原始data首次访问属性时才触发decompile()并删除原始数据见 E_B_L_C_.py。这意味着只读取bloc的目录信息而不触碰每个位图时可以避免不必要的解压开销。六、用 ttx 导出与导入位图表fontTools 的 ttx 工具可以把bloc/bdat转成 XML。导出时TTFont.saveXML通过bitmapGlyphDataFormat参数控制位图数据在 XML 中的呈现形式默认值为raw见 ttFont.py。从 E_B_D_T_.py 的xmlDataFunctions映射可以看到支持四种格式取值XML 元素说明rawrawimagedata十六进制 dump 原始字节默认rowrowimagedata按行输出十六进制适合逐行查看/修改bitwisebitwiseimagedata逐位 ASCII 艺术输出1显示为、0显示为.便于人工检查位图形状extfileextfileimagedata将每个位图写到输出目录bitmaps/strikeN/下的外部文件文件名即字形名含不安全字符的字形名会被百分号编码见_extFileName在命令行中使用 ttx 导出为row或bitwise格式的位图数据例如ttx -o font.ttx -b 1 font.ttf # 位图数据以 row 形式导出 ttx -o font.ttx -b 2 font.ttf # 位图数据以 bitwise 形式导出-b/--bitmap-glyph-data-format参数与bitmapGlyphDataFormat对应实际操作时可通过ttx -h查看当前版本的确切参数说明。bloc表的 XML 结构大致为bloc header version2.5/ strike index0 bitmapSizeTable sbitLineMetrics directionhori ... /sbitLineMetrics sbitLineMetrics directionvert ... /sbitLineMetrics startGlyphIndex value0/ endGlyphIndex value256/ ppemX value16/ ppemY value16/ bitDepth value1/ flags value1/ /bitmapSizeTable eblc_index_sub_table_1 imageFormat1 firstGlyphIndex0 lastGlyphIndex256 glyphLoc name.notdef id0/ ... /eblc_index_sub_table_1 /strike /bloc注意Strike.toXML中写入的注释见 E_B_L_C_.pyglyphLoc 的id与索引子表的firstGlyphIndex/lastGlyphIndex仅供参考、不会被读取编译时会根据字形名重新计算。与之配套bdat的 XML 以strikedata indexN分组每组内是各字形的位图元素如ebdt_bitmap_format_1。导入时直接ttx font.ttxfontTools 会从 XML 重建两张表并重新计算全部偏移。七、小结bloc是 AAT 位图定位表与bdat配对使用二者分别等价于 OpenType 的EBLC/EBDTfontTools 通过table__b_l_o_c(table_E_B_L_C_)与table__b_d_a_t(table_E_B_D_T_)两个轻量子类复用整套实现仅以dependencies与locatorName声明两者的配对关系bloc的解析核心是五种indexSubTable格式1~5与 strike/sbitLineMetrics模型全部实现在 E_B_L_C_.py 中编译时所有偏移都会重新计算XML 往返是安全的bitmapGlyphDataFormat提供了 raw/row/bitwise/extfile 四种位图数据导出方式方便人工检视与编辑。若需要深入源码建议从 Lib/fontTools/ttLib/tables/_b_l_o_c.py 出发依次阅读 E_B_L_C_.py、E_B_D_T_.py 与 BitmapGlyphMetrics.py即可完整理解bloc/bdat乃至EBLC/EBDT的全部读写逻辑。赞分享开发工具【免费下载链接】fonttoolsA library to manipulate font files from Python.项目地址https://gitcode.com/gh_mirrors/fo/fonttools点击查看免费下载相关推荐fontTools 中 bdatAAT 位图数据表的完整解析结构、bloc 配对机制与 ttx 实战fontTools 中 bdat AAT 位图数据表的完整解析结构、 bloc 配对机制与 ttx 实战 bdat 是 Apple Advanced Ty开发工具FontTools 中 CBDT 彩色位图表的实现解析格式 17–19、CBLC 定位与位图导出机制FontTools 中 CBDT 彩色位图表的实现解析格式 17–19、CBLC 定位与位图导出机制 CBDT Color Bitmap Data是 Op开发工具fontTools 中 CBLC 表转换器的解析彩色位图定位表的实现、XML 格式与验证方法fontTools 中 CBLC 表转换器的解析彩色位图定位表的实现、XML 格式与验证方法 CBLCColor Bitmap Location是 Ope开发工具上一篇Seraphine英雄联盟智能助手3分钟开启你的数据制胜之路下一篇G-Helper华硕笔记本性能优化的终极开源解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考