mirror of
https://github.com/foliojs/pdfkit.git
synced 2025-12-08 20:15:54 +00:00
189 lines
5.6 KiB
CoffeeScript
189 lines
5.6 KiB
CoffeeScript
Table = require '../table'
|
|
Data = require '../../data'
|
|
|
|
class CmapTable extends Table
|
|
parse: (data) ->
|
|
data.pos = @offset
|
|
|
|
@version = data.readUInt16()
|
|
tableCount = data.readUInt16()
|
|
@tables = []
|
|
@unicode = null
|
|
|
|
for i in [0...tableCount]
|
|
entry = new CmapEntry(data, @offset)
|
|
@tables.push entry
|
|
@unicode ?= entry if entry.isUnicode
|
|
|
|
return true
|
|
|
|
@encode: (charmap, encoding = 'macroman') ->
|
|
result = CmapEntry.encode(charmap, encoding)
|
|
table = new Data
|
|
|
|
table.writeUInt16 0 # version
|
|
table.writeUInt16 1 # tableCount
|
|
|
|
result.table = table.data.concat(result.subtable)
|
|
return result
|
|
|
|
class CmapEntry
|
|
constructor: (data, offset) ->
|
|
@platformID = data.readUInt16()
|
|
@encodingID = data.readShort()
|
|
@offset = offset + data.readInt()
|
|
|
|
data.pos = @offset
|
|
@format = data.readUInt16()
|
|
@length = data.readUInt16()
|
|
@language = data.readUInt16()
|
|
|
|
@isUnicode = (@platformID is 3 and @encodingID is 1 and @format is 4) or @platformID is 0 and @format is 4
|
|
|
|
@codeMap = {}
|
|
switch @format
|
|
when 0
|
|
for i in [0...256]
|
|
@codeMap[i] = data.readByte()
|
|
|
|
when 4
|
|
segCountX2 = data.readUInt16()
|
|
segCount = segCountX2 / 2
|
|
|
|
data.pos += 6 # skip searching hints
|
|
endCode = (data.readUInt16() for i in [0...segCount])
|
|
data.pos += 2 # skip reserved value
|
|
|
|
startCode = (data.readUInt16() for i in [0...segCount])
|
|
idDelta = (data.readUInt16() for i in [0...segCount])
|
|
idRangeOffset = (data.readUInt16() for i in [0...segCount])
|
|
|
|
count = @length - data.pos + @offset
|
|
glyphIds = (data.readUInt16() for i in [0...count])
|
|
|
|
for tail, i in endCode
|
|
start = startCode[i]
|
|
for code in [start..tail]
|
|
if idRangeOffset[i] is 0
|
|
glyphId = code + idDelta[i]
|
|
else
|
|
index = idRangeOffset[i] / 2 + (code - start) - (segCount - i)
|
|
glyphId = glyphIds[index] or 0
|
|
glyphId += idDelta[i] if glyphId isnt 0
|
|
|
|
@codeMap[code] = glyphId & 0xFFFF
|
|
|
|
@encode: (charmap, encoding) ->
|
|
subtable = new Data
|
|
codes = Object.keys(charmap).sort (a, b) -> a - b
|
|
|
|
switch encoding
|
|
when 'macroman'
|
|
id = 0
|
|
indexes = (0 for i in [0...256])
|
|
map = { 0: 0 }
|
|
codeMap = {}
|
|
|
|
for code in codes
|
|
map[charmap[code]] ?= ++id
|
|
codeMap[code] =
|
|
old: charmap[code]
|
|
new: map[charmap[code]]
|
|
|
|
indexes[code] = map[charmap[code]]
|
|
|
|
subtable.writeUInt16 1 # platformID
|
|
subtable.writeUInt16 0 # encodingID
|
|
subtable.writeUInt32 12 # offset
|
|
subtable.writeUInt16 0 # format
|
|
subtable.writeUInt16 262 # length
|
|
subtable.writeUInt16 0 # language
|
|
subtable.write indexes # glyph indexes
|
|
|
|
result =
|
|
charMap: codeMap
|
|
subtable: subtable.data
|
|
maxGlyphID: id + 1
|
|
|
|
when 'unicode'
|
|
startCodes = []
|
|
endCodes = []
|
|
nextID = 0
|
|
map = {}
|
|
charMap = {}
|
|
last = diff = null
|
|
|
|
for code in codes
|
|
old = charmap[code]
|
|
map[old] ?= ++nextID
|
|
charMap[code] =
|
|
old: old
|
|
new: map[old]
|
|
|
|
delta = map[old] - code
|
|
if not last? or delta isnt diff
|
|
endCodes.push last if last
|
|
startCodes.push code
|
|
diff = delta
|
|
|
|
last = code
|
|
|
|
endCodes.push last if last
|
|
endCodes.push 0xFFFF
|
|
startCodes.push 0xFFFF
|
|
|
|
segCount = startCodes.length
|
|
segCountX2 = segCount * 2
|
|
searchRange = 2 * Math.pow(Math.log(segCount) / Math.LN2, 2)
|
|
entrySelector = Math.log(searchRange / 2) / Math.LN2
|
|
rangeShift = 2 * segCount - searchRange
|
|
|
|
deltas = []
|
|
rangeOffsets = []
|
|
glyphIDs = []
|
|
|
|
for startCode, i in startCodes
|
|
endCode = endCodes[i]
|
|
|
|
if startCode is 0xFFFF
|
|
deltas.push 0
|
|
rangeOffsets.push 0
|
|
break
|
|
|
|
startGlyph = charMap[startCode].new
|
|
if startCode - startGlyph >= 0x8000
|
|
deltas.push 0
|
|
rangeOffsets.push 2 * (glyphIDs.length + segCount - i)
|
|
|
|
for code in [startCode..endCode]
|
|
glyphIDs.push charMap[code].new
|
|
|
|
else
|
|
deltas.push startGlyph - startCode
|
|
rangeOffsets.push 0
|
|
|
|
subtable.writeUInt16 3 # platformID
|
|
subtable.writeUInt16 1 # encodingID
|
|
subtable.writeUInt32 12 # offset
|
|
subtable.writeUInt16 4 # format
|
|
subtable.writeUInt16 16 + segCount * 8 + glyphIDs.length * 2 # length
|
|
subtable.writeUInt16 0 # language
|
|
subtable.writeUInt16 segCountX2
|
|
subtable.writeUInt16 searchRange
|
|
subtable.writeUInt16 entrySelector
|
|
subtable.writeUInt16 rangeShift
|
|
|
|
subtable.writeUInt16 code for code in endCodes
|
|
subtable.writeUInt16 0 # reserved value
|
|
subtable.writeUInt16 code for code in startCodes
|
|
|
|
subtable.writeUInt16 delta for delta in deltas
|
|
subtable.writeUInt16 offset for offset in rangeOffsets
|
|
subtable.writeUInt16 id for id in glyphIDs
|
|
|
|
result =
|
|
charMap: charMap
|
|
subtable: subtable.data
|
|
maxGlyphID: nextID + 1
|
|
|
|
module.exports = CmapTable |