222 lines
6.3 KiB
JavaScript
222 lines
6.3 KiB
JavaScript
/**
|
||
* @file ttfwriter.js
|
||
* @author mengke01
|
||
* @date
|
||
* @description
|
||
* 写ttf文件
|
||
*/
|
||
|
||
|
||
define(
|
||
function(require) {
|
||
|
||
var Writer = require('./writer');
|
||
var Directory = require('./table/directory');
|
||
var supportTables = require('./table/support');
|
||
var checkSum = require('./util/checkSum');
|
||
var error = require('./error');
|
||
|
||
var reduceGlyf = require('./util/reduceGlyf');
|
||
var pathCeil = require('graphics/pathCeil');
|
||
|
||
// 支持写的表, 注意表顺序
|
||
var tableList = [
|
||
'OS/2',
|
||
'cmap',
|
||
'glyf',
|
||
'head',
|
||
'hhea',
|
||
'hmtx',
|
||
'loca',
|
||
'maxp',
|
||
'name',
|
||
'post'
|
||
];
|
||
|
||
|
||
/**
|
||
* 处理ttf结构,以便于写
|
||
*
|
||
* @param {ttfObject} ttf ttf数据结构
|
||
*/
|
||
function resolve(ttf) {
|
||
|
||
// 头部信息
|
||
ttf.numTables = tableList.length;
|
||
ttf.entrySelector = Math.floor(Math.log(tableList.length)/Math.LN2);
|
||
ttf.searchRange = Math.pow(2, ttf.entrySelector) * 16;
|
||
ttf.rangeShift = tableList.length * 16 - ttf.searchRange;
|
||
|
||
// 重置校验码
|
||
ttf.head.checkSumAdjustment = 0;
|
||
ttf.head.magickNumber = 0x5F0F3CF5;
|
||
|
||
if (typeof(ttf.head.created) == 'string') {
|
||
ttf.head.created = /^\d+$/.test(ttf.head.created) ? +ttf.head.created : Date.parse(ttf.head.created);
|
||
}
|
||
|
||
ttf.head.modified = Date.now();
|
||
|
||
if (!ttf.glyf || ttf.glyf.length === 0) {
|
||
error.raise(10201);
|
||
}
|
||
|
||
var checkUnicodeRepeat = {}; // 检查是否有重复代码点
|
||
|
||
// 将glyf的代码点按小到大排序
|
||
ttf.glyf.forEach(function(glyf, index) {
|
||
if (glyf.unicode) {
|
||
glyf.unicode = glyf.unicode.sort();
|
||
|
||
glyf.unicode.forEach(function(u) {
|
||
if (checkUnicodeRepeat[u]) {
|
||
error.raise(10200, index);
|
||
}
|
||
else {
|
||
checkUnicodeRepeat[u] = true;
|
||
}
|
||
});
|
||
|
||
}
|
||
|
||
if (!glyf.compound && glyf.contours) {
|
||
|
||
// 整数化
|
||
glyf.contours.forEach(function(contour) {
|
||
pathCeil(contour);
|
||
});
|
||
|
||
// 缩减glyf
|
||
reduceGlyf(glyf);
|
||
}
|
||
|
||
// 整数化
|
||
glyf.xMin = Math.round(glyf.xMin || 0);
|
||
glyf.xMax = Math.round(glyf.xMax || 0);
|
||
glyf.yMin = Math.round(glyf.yMin || 0);
|
||
glyf.yMax = Math.round(glyf.yMax || 0);
|
||
glyf.leftSideBearing = Math.round(glyf.leftSideBearing || 0);
|
||
glyf.advanceWidth = Math.round(glyf.advanceWidth || 0);
|
||
|
||
});
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* 写ttf文件
|
||
*
|
||
* @param {ttfObject} ttf ttf数据结构
|
||
* @return {ArrayBuffer} 字节流
|
||
*/
|
||
function write(ttf) {
|
||
|
||
// 用来做写入缓存的对象,用完后删掉
|
||
ttf.support = {};
|
||
|
||
// head + directory
|
||
var ttfSize = 12 + tableList.length * 16;
|
||
var ttfHeadOffset = 0; // 记录head的偏移
|
||
// 构造tables
|
||
ttf.support.tables = [];
|
||
tableList.forEach(function(tableName) {
|
||
var offset = ttfSize;
|
||
var tableSize = new supportTables[tableName]().size(ttf); // 原始的表大小
|
||
var size = tableSize; // 对对齐后的表大小
|
||
|
||
if (tableName == 'head') {
|
||
ttfHeadOffset = offset;
|
||
}
|
||
|
||
// 4字节对齐
|
||
if (size % 4) {
|
||
size += 4 - size % 4;
|
||
}
|
||
|
||
ttf.support.tables.push({
|
||
name: tableName,
|
||
checkSum: 0,
|
||
offset: offset,
|
||
length: tableSize,
|
||
size: size
|
||
});
|
||
|
||
ttfSize += size;
|
||
});
|
||
|
||
var writer = new Writer(new ArrayBuffer(ttfSize));
|
||
|
||
// 写头部
|
||
writer.writeFixed(ttf.version);
|
||
writer.writeUint16(ttf.numTables);
|
||
writer.writeUint16(ttf.searchRange);
|
||
writer.writeUint16(ttf.entrySelector);
|
||
writer.writeUint16(ttf.rangeShift);
|
||
|
||
// 写表偏移
|
||
!new Directory().write(writer, ttf);
|
||
|
||
// 写支持的表数据
|
||
ttf.support.tables.forEach(function(table) {
|
||
|
||
var tableStart = writer.offset;
|
||
!new supportTables[table.name]().write(writer, ttf);
|
||
|
||
if (table.length % 4) {
|
||
// 对齐字节
|
||
writer.writeEmpty(4 - table.length % 4);
|
||
}
|
||
|
||
// 计算校验和
|
||
table.checkSum = checkSum(writer.getBuffer(), tableStart, table.size);
|
||
|
||
});
|
||
|
||
// 重新写入每个表校验和
|
||
ttf.support.tables.forEach(function(table, index) {
|
||
var offset = 12 + index * 16 + 4;
|
||
writer.writeUint32(table.checkSum, offset);
|
||
});
|
||
|
||
// 写入总校验和
|
||
var ttfCheckSum = (0xB1B0AFBA - checkSum(writer.getBuffer()) + 0x100000000) % 0x100000000;
|
||
writer.writeUint32(ttfCheckSum, ttfHeadOffset + 8);
|
||
|
||
delete ttf.support;
|
||
|
||
var buffer = writer.getBuffer();
|
||
writer.dispose();
|
||
|
||
return buffer;
|
||
}
|
||
|
||
|
||
/**
|
||
* TTFWriter的构造函数
|
||
*
|
||
* @constructor
|
||
*/
|
||
function TTFWriter() {
|
||
}
|
||
|
||
/**
|
||
* 写一个ttf字体结构
|
||
*
|
||
* @return {ArrayBuffer} 缓冲数组
|
||
*/
|
||
TTFWriter.prototype.write = function(ttf) {
|
||
resolve.call(this, ttf);
|
||
var buffer = write.call(this, ttf);
|
||
return buffer;
|
||
};
|
||
|
||
/**
|
||
* 注销
|
||
*/
|
||
TTFWriter.prototype.dispose = function() {
|
||
};
|
||
|
||
return TTFWriter;
|
||
}
|
||
);
|