关于ttc(Font Collection File)转ttf(True Type File)和N个ttf合并成ttc的问题

ttc的头文件部分

伪代码结构体:

typedef struct tag_TTC_Header

{

    char tag[4];  //"ttcf"

    uint16 ver_h;  //1/2

    uint16 ver_l;  //0

    uint32 directoryCount;  //N

    uint32 directorys[directoryCount];  //N*4bytes

//Sig_Object here (option)

}TTC_Header;

typedef struct tag_Sig_Object

{

    char tag[4];

    uint32 length;

    uint32 offset;

}Sig_Object;

解释一下:

这里用到的数据类都是大端(Big Endian)写入;如ver_h(uint16)=1写出为 00 01;

directoryCount(uint32)=4写出是 00 00 00 04

tag[4]固定是“ttcf”

ver_h通常是1或者2;版本高位=1通常是旧版的,可以没有签字(Sig_Object);但是也不绝对,我看到simsun.ttc就是这个字节=1,但是也有Sig_Object结构。版本高位=2通常都是有Sig_Object结构(微软上的解释等于2时包括Sig_Object部分)

ver_l通常为0;版本低位;

上述的版本描述不是字体自身的版本,它是ttc结构的描述,所以暂时我理解是1可以随便使用,2是组织机构那些有签字的使用

directoryCount是描述了这个ttc文件包含多少个字体(介绍里面说不一定都是ttf,但是我这里默认只包含ttf,后面的描述也是这样)

directorys[]是一个文件偏量的数组;例如第一个字体在ttc文件上的偏移是0x40,写入为 00 00 00 40 ;第二个字体的偏移是0x00054438,写入为 00 05 44 38;。。。同样看出来都是大端写入的,对于小端读写编码会麻烦一点点。

写完了文件偏移量后,如果有签名就将sig这个结构填上,重复说一遍,大端写入!签名要注意了,数据块的尺寸放在tag后面的,呵呵,不要混乱了。

接下来是ttf的结构,ttc也是有的,其中offset table是一样的,font table的偏移量是会变化的

typedef struct tag_Offset_Table

{

    char tag[4];  //00 01 00 00 or 'OTTO'

    uint16 numTables;   //x font table

    uint16 searchRange;  //256 (Maximum power of 2 <= numTables) x 16.

    uint16 entrySelector;  //4 Log2(maximum power of 2 <= numTables).

    uint16 rangeShift;   //48 NumTables x 16-searchRange.

}Offset_Table;

tag 通常描述版本1.0还是2.0,如果是OTTO表示OpenType字体包含CFF数据(知道CFF是一个表名就可以了,暂时不深挖);不管是解包TTC还是打包TTC,不用管Offset Table的信息,直接复制就好,当然必须读出numTables的大小。

暂时不论对错,先写下个人的理解,如下:

searchRange= t_numTables*sizeof(Font_Table) = t_numTables*16;

其中t_numTables有限制是[2,16],也就是说searchRange的范围是32到256;

t_numTables = numTables>16?16:numTables;

t_numTables = t_numTables<2?0:t_numTables;  //0代表失败

entrySelector=(int)log2(t_numTables); 它的范围[1,4];

rangeShift是numTables*sizeof(Font_Table)-searchRange = numTables*16-searchRange;如果numTables在2到16的范围,那么这里rangeShift=0;当numTables>16时,rangeShift为正数。

typedef struct tag_Font_Table

{

    char tag[4];

    uint32 checkSum;

    uint32 offset;

    uint32 length;

}Font_Table;

根据Offset Table得到numTables;这里可以知道需要读取sizeof(Font_Table)* numTables个字节,然后一个个对应填入;从而获得每一个font table对应的偏移和大小;

tag有很多,例如“name”代表字体名字,“cmap”是字符映射表等等,解包和打包TTC只需要改offset这个字节,其他的不用管。

Font_Table成员的理解:

tag:标签,表示。

checkSum:很简单地对数据字节加校验;类似这样的操作:

int sum=0;

for(int i=0;i

{

   sum += data[i];

}

具体会不会重复,那就看运气了,对单个文件这个重复的几率不大,言尽于此。

offset:当前文件的偏移量,也就是读数据的开始位置

length:数据的大小,字面意思,没什么好解析的。

对于解包TTC,每一个单独的TTF都是有Offset table+N*font table组成;因为ttf初始偏移为0;那么就要将对应font table对应的offset根据ttf文件写入量进行修改。

对于打包TTC,要根据ttc写入量对font table的offset进行修改。如果要做数据共用的话,要先计算data的checkSum,能算一下md5更准确,然后将已经写入的包和checkSum/Md5做一个表查询,如果遇到相同的数据,则将对应font table的offset改到相应的值,而不需要重复写入。(这个有点麻烦,我没写)

以下是一些资料

关于TTF的翻译文件(工程上传GitHub之后发现的,中文描述比较全):htt-ps://github.com/luckyaibin/truetypefontparsetoy/blob/master/truetypefont.org

微软关于字体的描述:htt-ps://docs.microsoft.com/zh-cn/typography/opbuildpdf/TOC.pdf

获取TrueType字体信息:htt-ps://blog.csdn.net/kwfly/article/details/50986338?utm_source=blogxgwz2

本文相关的代码:htt-ps://github.com/fermi1981/TTC_TTF

你可能感兴趣的:(字体相关,TTC,TTF,转换)