You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
3.8 KiB
160 lines
3.8 KiB
var HEADER = [66, 77, 70] |
|
|
|
module.exports = function readBMFontBinary(buf) { |
|
if (buf.length < 6) |
|
throw new Error('invalid buffer length for BMFont') |
|
|
|
var header = HEADER.every(function(byte, i) { |
|
return buf.readUInt8(i) === byte |
|
}) |
|
|
|
if (!header) |
|
throw new Error('BMFont missing BMF byte header') |
|
|
|
var i = 3 |
|
var vers = buf.readUInt8(i++) |
|
if (vers > 3) |
|
throw new Error('Only supports BMFont Binary v3 (BMFont App v1.10)') |
|
|
|
var target = { kernings: [], chars: [] } |
|
for (var b=0; b<5; b++) |
|
i += readBlock(target, buf, i) |
|
return target |
|
} |
|
|
|
function readBlock(target, buf, i) { |
|
if (i > buf.length-1) |
|
return 0 |
|
|
|
var blockID = buf.readUInt8(i++) |
|
var blockSize = buf.readInt32LE(i) |
|
i += 4 |
|
|
|
switch(blockID) { |
|
case 1: |
|
target.info = readInfo(buf, i) |
|
break |
|
case 2: |
|
target.common = readCommon(buf, i) |
|
break |
|
case 3: |
|
target.pages = readPages(buf, i, blockSize) |
|
break |
|
case 4: |
|
target.chars = readChars(buf, i, blockSize) |
|
break |
|
case 5: |
|
target.kernings = readKernings(buf, i, blockSize) |
|
break |
|
} |
|
return 5 + blockSize |
|
} |
|
|
|
function readInfo(buf, i) { |
|
var info = {} |
|
info.size = buf.readInt16LE(i) |
|
|
|
var bitField = buf.readUInt8(i+2) |
|
info.smooth = (bitField >> 7) & 1 |
|
info.unicode = (bitField >> 6) & 1 |
|
info.italic = (bitField >> 5) & 1 |
|
info.bold = (bitField >> 4) & 1 |
|
|
|
//fixedHeight is only mentioned in binary spec |
|
if ((bitField >> 3) & 1) |
|
info.fixedHeight = 1 |
|
|
|
info.charset = buf.readUInt8(i+3) || '' |
|
info.stretchH = buf.readUInt16LE(i+4) |
|
info.aa = buf.readUInt8(i+6) |
|
info.padding = [ |
|
buf.readInt8(i+7), |
|
buf.readInt8(i+8), |
|
buf.readInt8(i+9), |
|
buf.readInt8(i+10) |
|
] |
|
info.spacing = [ |
|
buf.readInt8(i+11), |
|
buf.readInt8(i+12) |
|
] |
|
info.outline = buf.readUInt8(i+13) |
|
info.face = readStringNT(buf, i+14) |
|
return info |
|
} |
|
|
|
function readCommon(buf, i) { |
|
var common = {} |
|
common.lineHeight = buf.readUInt16LE(i) |
|
common.base = buf.readUInt16LE(i+2) |
|
common.scaleW = buf.readUInt16LE(i+4) |
|
common.scaleH = buf.readUInt16LE(i+6) |
|
common.pages = buf.readUInt16LE(i+8) |
|
var bitField = buf.readUInt8(i+10) |
|
common.packed = 0 |
|
common.alphaChnl = buf.readUInt8(i+11) |
|
common.redChnl = buf.readUInt8(i+12) |
|
common.greenChnl = buf.readUInt8(i+13) |
|
common.blueChnl = buf.readUInt8(i+14) |
|
return common |
|
} |
|
|
|
function readPages(buf, i, size) { |
|
var pages = [] |
|
var text = readNameNT(buf, i) |
|
var len = text.length+1 |
|
var count = size / len |
|
for (var c=0; c<count; c++) { |
|
pages[c] = buf.slice(i, i+text.length).toString('utf8') |
|
i += len |
|
} |
|
return pages |
|
} |
|
|
|
function readChars(buf, i, blockSize) { |
|
var chars = [] |
|
|
|
var count = blockSize / 20 |
|
for (var c=0; c<count; c++) { |
|
var char = {} |
|
var off = c*20 |
|
char.id = buf.readUInt32LE(i + 0 + off) |
|
char.x = buf.readUInt16LE(i + 4 + off) |
|
char.y = buf.readUInt16LE(i + 6 + off) |
|
char.width = buf.readUInt16LE(i + 8 + off) |
|
char.height = buf.readUInt16LE(i + 10 + off) |
|
char.xoffset = buf.readInt16LE(i + 12 + off) |
|
char.yoffset = buf.readInt16LE(i + 14 + off) |
|
char.xadvance = buf.readInt16LE(i + 16 + off) |
|
char.page = buf.readUInt8(i + 18 + off) |
|
char.chnl = buf.readUInt8(i + 19 + off) |
|
chars[c] = char |
|
} |
|
return chars |
|
} |
|
|
|
function readKernings(buf, i, blockSize) { |
|
var kernings = [] |
|
var count = blockSize / 10 |
|
for (var c=0; c<count; c++) { |
|
var kern = {} |
|
var off = c*10 |
|
kern.first = buf.readUInt32LE(i + 0 + off) |
|
kern.second = buf.readUInt32LE(i + 4 + off) |
|
kern.amount = buf.readInt16LE(i + 8 + off) |
|
kernings[c] = kern |
|
} |
|
return kernings |
|
} |
|
|
|
function readNameNT(buf, offset) { |
|
var pos=offset |
|
for (; pos<buf.length; pos++) { |
|
if (buf[pos] === 0x00) |
|
break |
|
} |
|
return buf.slice(offset, pos) |
|
} |
|
|
|
function readStringNT(buf, offset) { |
|
return readNameNT(buf, offset).toString('utf8') |
|
} |