字体文件格式

    技术2024-11-16  30

     

    做个简单的总结,最近缺少激情和动力。做事要顺其自然,顺势而发,做必要的,干这些也如此。 先总结freetype的框架 然后就是truetype的一些数据。 ======================================== 感觉这些东西都需要慢慢一步步的积累,一下子的话走不远。

    先总结freetype的框架吧。freetype用C实现面向对象,简单的分析后,觉得整个库做得简单,实用,没有太多累赘,顺其自然,没有太多刻意的封装,累赘的接口调用,用起来方便,看起来舒心!

     freetype设计得比较好的有几个模块。 stream,system, module,library, face 1,library管理着多个module,(sfnt,type1,src文件夹下除了base之外的其他模块。) 2,module管理着各个模块分析文件的接口部分。例如 sfnt_interface;可以load_loca,load_cmap,lookup_table,goto_table;等。 3,stream,system封装一系列底层相关的api,而上层提供的stream给module的接口做分析用。 4,FT_Face,TT_Face,TT_Face 是FT_Face的封装,给内部用的,外部用户只有FT_Face,而TT_Face则可以做分析数据用。在中间这层转换做隔离封装用。 ----------------------------------------------------------------------- 至于TrueType的文件格式分析: 1,注意truetype文件是以大端序存储的字节序,读取数据时要做转换。 2,最恍然大悟的是分析了cmap表,字符编码本质就是给映射用的。最终还是流到图元指令集。其实如果字体支持gbk编码的话,可以不做unicode转换也能够显示。不过貌似绘图API只支持unicode的。format0存储的是 ansii表的图元索引映射,format4存储的是unicode区段的图元索引映射。format4 idRangeOffset不为0时,则根据 *(idRangeOffset[i] / 2 + (c - startCount[i]) + &idRangeOffset[i]) 计算出,注意其中的字节数偏移,要换算为两个字节。 3,另外一个有趣点的是glyf表,替换两个字体文件的glyf表,或许可以做点伪造字体之类的事。 4,分析文件的一个顿悟,文件格式存储的是一个数据结构。 ------------------------------------------------------------------------- 做文件格式分析,常常感悟最多,毕竟文件格式是存储的单元,也是数据的聚合。 附cmap表分析代码一段: void ParserCmap(char* buff, char* buffend) { char* buff_start = buff; USHORT version = readUnsignedShort(buff); buff += 2; USHORT tables = readUnsignedShort(buff); buff += 2; printf("version: %d, tables: %d/n", version, tables); int nTbIndex = 0; for (; nTbIndex < tables; ++nTbIndex) { USHORT flatformId = readUnsignedShort(buff); buff += 2; USHORT encodingId = readUnsignedShort(buff); buff += 2; ULONG offset = readUnsignedLong(buff); buff += 4; printf("flatformId: %d, encodingId: %d, offset: %d/n", flatformId, encodingId, offset); char* table_start = buff_start + offset; USHORT formatId = readUnsignedShort(table_start); table_start += 2; if (formatId == 0) { printf("=====================format 0====================/n"); USHORT length = readUnsignedShort(table_start); table_start += 2; USHORT version = readUnsignedShort(table_start); table_start += 2; printf("length: %d, version: %d/n", length, version); printf("byte: /n"); int i = 0; for (; i < length; ++i) { printf("%c: 0x%x ", i, (*table_start & 0xFF)); table_start++; } printf("/n"); } else if (formatId == 4) { printf("====================format 4====================/n"); USHORT length = readUnsignedShort(table_start); table_start += 2; USHORT version = readUnsignedShort(table_start); table_start += 2; USHORT segDblCounts = readUnsignedShort(table_start); table_start += 2; USHORT searchRange = readUnsignedShort(table_start); table_start += 2; USHORT entrySelector = readUnsignedShort(table_start); table_start += 2; USHORT rangeShift = readUnsignedShort(table_start); table_start += 2; printf("length: %d, version: %d, segDblCounts: %d, searchRange: %d, entrySelector: %d, rangeShift: %d/n", length, version, segDblCounts, searchRange, entrySelector, rangeShift); char* endCounts = table_start; char* startCounts = table_start + segDblCounts + 2; char* delta = startCounts + segDblCounts; char* rangeOffset = delta + segDblCounts; char* glyfId = rangeOffset + segDblCounts; USHORT segCounts = segDblCounts >> 1; USHORT segIndex = 0; printf("endCounts startCounts delta rangeOffset/n"); for (; segIndex < segCounts; ++segIndex) { USHORT endCode = readUnsignedShort(endCounts); endCounts += 2; USHORT startCode = readUnsignedShort(startCounts); startCounts += 2; USHORT del = readUnsignedShort(delta); delta += 2; USHORT offset = readUnsignedShort(rangeOffset); rangeOffset += 2; //for wingdings find 0xf031 match 49:'1' /* if (segIndex == 0) { USHORT dis = offset / 2 + 0xf031 - 0xf020; rangeOffset += dis * 2 - 2; USHORT id = readUnsignedShort(rangeOffset); printf("0xf031: 0x%x/n", id); } */ printf("0x%x 0x%x %d %d/n", endCode, startCode, del, offset); } int glyfIndex = 0; while (glyfId < buffend) { USHORT glyf = readUnsignedShort(glyfId); glyfId += 2; printf("%d: 0x%x ", glyfIndex, (glyf & 0xFFFF)); glyfIndex++; } printf("/n"); } } } 

     

    最新回复(0)