index.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. var HEADER = [66, 77, 70]
  2. module.exports = function readBMFontBinary(buf) {
  3. if (buf.length < 6)
  4. throw new Error('invalid buffer length for BMFont')
  5. var header = HEADER.every(function(byte, i) {
  6. return buf.readUInt8(i) === byte
  7. })
  8. if (!header)
  9. throw new Error('BMFont missing BMF byte header')
  10. var i = 3
  11. var vers = buf.readUInt8(i++)
  12. if (vers > 3)
  13. throw new Error('Only supports BMFont Binary v3 (BMFont App v1.10)')
  14. var target = { kernings: [], chars: [] }
  15. for (var b=0; b<5; b++)
  16. i += readBlock(target, buf, i)
  17. return target
  18. }
  19. function readBlock(target, buf, i) {
  20. if (i > buf.length-1)
  21. return 0
  22. var blockID = buf.readUInt8(i++)
  23. var blockSize = buf.readInt32LE(i)
  24. i += 4
  25. switch(blockID) {
  26. case 1:
  27. target.info = readInfo(buf, i)
  28. break
  29. case 2:
  30. target.common = readCommon(buf, i)
  31. break
  32. case 3:
  33. target.pages = readPages(buf, i, blockSize)
  34. break
  35. case 4:
  36. target.chars = readChars(buf, i, blockSize)
  37. break
  38. case 5:
  39. target.kernings = readKernings(buf, i, blockSize)
  40. break
  41. }
  42. return 5 + blockSize
  43. }
  44. function readInfo(buf, i) {
  45. var info = {}
  46. info.size = buf.readInt16LE(i)
  47. var bitField = buf.readUInt8(i+2)
  48. info.smooth = (bitField >> 7) & 1
  49. info.unicode = (bitField >> 6) & 1
  50. info.italic = (bitField >> 5) & 1
  51. info.bold = (bitField >> 4) & 1
  52. //fixedHeight is only mentioned in binary spec
  53. if ((bitField >> 3) & 1)
  54. info.fixedHeight = 1
  55. info.charset = buf.readUInt8(i+3) || ''
  56. info.stretchH = buf.readUInt16LE(i+4)
  57. info.aa = buf.readUInt8(i+6)
  58. info.padding = [
  59. buf.readInt8(i+7),
  60. buf.readInt8(i+8),
  61. buf.readInt8(i+9),
  62. buf.readInt8(i+10)
  63. ]
  64. info.spacing = [
  65. buf.readInt8(i+11),
  66. buf.readInt8(i+12)
  67. ]
  68. info.outline = buf.readUInt8(i+13)
  69. info.face = readStringNT(buf, i+14)
  70. return info
  71. }
  72. function readCommon(buf, i) {
  73. var common = {}
  74. common.lineHeight = buf.readUInt16LE(i)
  75. common.base = buf.readUInt16LE(i+2)
  76. common.scaleW = buf.readUInt16LE(i+4)
  77. common.scaleH = buf.readUInt16LE(i+6)
  78. common.pages = buf.readUInt16LE(i+8)
  79. var bitField = buf.readUInt8(i+10)
  80. common.packed = 0
  81. common.alphaChnl = buf.readUInt8(i+11)
  82. common.redChnl = buf.readUInt8(i+12)
  83. common.greenChnl = buf.readUInt8(i+13)
  84. common.blueChnl = buf.readUInt8(i+14)
  85. return common
  86. }
  87. function readPages(buf, i, size) {
  88. var pages = []
  89. var text = readNameNT(buf, i)
  90. var len = text.length+1
  91. var count = size / len
  92. for (var c=0; c<count; c++) {
  93. pages[c] = buf.slice(i, i+text.length).toString('utf8')
  94. i += len
  95. }
  96. return pages
  97. }
  98. function readChars(buf, i, blockSize) {
  99. var chars = []
  100. var count = blockSize / 20
  101. for (var c=0; c<count; c++) {
  102. var char = {}
  103. var off = c*20
  104. char.id = buf.readUInt32LE(i + 0 + off)
  105. char.x = buf.readUInt16LE(i + 4 + off)
  106. char.y = buf.readUInt16LE(i + 6 + off)
  107. char.width = buf.readUInt16LE(i + 8 + off)
  108. char.height = buf.readUInt16LE(i + 10 + off)
  109. char.xoffset = buf.readInt16LE(i + 12 + off)
  110. char.yoffset = buf.readInt16LE(i + 14 + off)
  111. char.xadvance = buf.readInt16LE(i + 16 + off)
  112. char.page = buf.readUInt8(i + 18 + off)
  113. char.chnl = buf.readUInt8(i + 19 + off)
  114. chars[c] = char
  115. }
  116. return chars
  117. }
  118. function readKernings(buf, i, blockSize) {
  119. var kernings = []
  120. var count = blockSize / 10
  121. for (var c=0; c<count; c++) {
  122. var kern = {}
  123. var off = c*10
  124. kern.first = buf.readUInt32LE(i + 0 + off)
  125. kern.second = buf.readUInt32LE(i + 4 + off)
  126. kern.amount = buf.readInt16LE(i + 8 + off)
  127. kernings[c] = kern
  128. }
  129. return kernings
  130. }
  131. function readNameNT(buf, offset) {
  132. var pos=offset
  133. for (; pos<buf.length; pos++) {
  134. if (buf[pos] === 0x00)
  135. break
  136. }
  137. return buf.slice(offset, pos)
  138. }
  139. function readStringNT(buf, offset) {
  140. return readNameNT(buf, offset).toString('utf8')
  141. }