|
|
|
@ -9,6 +9,7 @@ import kotlin.experimental.and |
|
|
|
|
* @see <a href="https://docs.microsoft.com/en-us/typography/opentype/spec/">获取详情</a> |
|
|
|
|
* @see <a href="https://photopea.github.io/Typr.js/demo/index.html">基于Javascript的TTF解析器</a> |
|
|
|
|
*/ |
|
|
|
|
@ExperimentalUnsignedTypes |
|
|
|
|
class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
private class Header { |
|
|
|
|
var majorVersion: UShort = 0u |
|
|
|
@ -95,7 +96,7 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
var offset: UInt = 0u |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private class CmapFormat0 { |
|
|
|
|
private class CmapFormat0 { |
|
|
|
|
var format: UShort = 0u |
|
|
|
|
var length: UShort = 0u |
|
|
|
|
var language: UShort = 0u |
|
|
|
@ -152,12 +153,12 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
|
|
|
|
|
private class ByteArrayReader(var Buffer: ByteArray, var Index: Int) { |
|
|
|
|
fun ReadUIntX(len: Long): ULong { |
|
|
|
|
var result: ULong = 0u; |
|
|
|
|
var result: ULong = 0u |
|
|
|
|
for (i in 0 until len) { |
|
|
|
|
result.shl(8); |
|
|
|
|
result.shl(8) |
|
|
|
|
result = result or Buffer[Index++].toULong() |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
return result |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun ReadUInt64(): ULong { |
|
|
|
@ -203,7 +204,7 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
for (i in 0 until len) { |
|
|
|
|
result[i] = Buffer[Index++] |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
return result |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun GetUInt16Array(len: Int): ArrayList<UShort> { |
|
|
|
@ -212,7 +213,7 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
for (i in 0 until len) { |
|
|
|
|
result[i] = ReadUInt16() |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
return result |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun GetInt16Array(len: Int): ArrayList<Short> { |
|
|
|
@ -221,7 +222,7 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
for (i in 0 until len) { |
|
|
|
|
result[i] = ReadInt16() |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
return result |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -240,15 +241,15 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
FontReader = ByteArrayReader(Font, 0) |
|
|
|
|
// 获取文件头 |
|
|
|
|
fileHeader.majorVersion = FontReader.ReadUInt16() |
|
|
|
|
fileHeader.minorVersion = FontReader.ReadUInt16(); |
|
|
|
|
fileHeader.numOfTables = FontReader.ReadUInt16(); |
|
|
|
|
fileHeader.searchRange = FontReader.ReadUInt16(); |
|
|
|
|
fileHeader.entrySelector = FontReader.ReadUInt16(); |
|
|
|
|
fileHeader.rangeShift = FontReader.ReadUInt16(); |
|
|
|
|
fileHeader.minorVersion = FontReader.ReadUInt16() |
|
|
|
|
fileHeader.numOfTables = FontReader.ReadUInt16() |
|
|
|
|
fileHeader.searchRange = FontReader.ReadUInt16() |
|
|
|
|
fileHeader.entrySelector = FontReader.ReadUInt16() |
|
|
|
|
fileHeader.rangeShift = FontReader.ReadUInt16() |
|
|
|
|
// 获取目录 |
|
|
|
|
for (i in 0 until fileHeader.numOfTables.toInt()) { |
|
|
|
|
val tag = FontReader.ReadStrings(4, Charsets.US_ASCII) |
|
|
|
|
val t = Directory(); |
|
|
|
|
val t = Directory() |
|
|
|
|
t.tag = tag |
|
|
|
|
t.checkSum = FontReader.ReadUInt32() |
|
|
|
|
t.offset = FontReader.ReadUInt32() |
|
|
|
@ -258,10 +259,10 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
// 解析表 name (字体信息,包含版权、名称、作者等...) |
|
|
|
|
for (Temp in directorys) { |
|
|
|
|
if (Temp.tag == "name") { |
|
|
|
|
FontReader.Index = Temp.offset.toInt(); |
|
|
|
|
name.format = FontReader.ReadUInt16(); |
|
|
|
|
name.count = FontReader.ReadUInt16(); |
|
|
|
|
name.stringOffset = FontReader.ReadUInt16(); |
|
|
|
|
FontReader.Index = Temp.offset.toInt() |
|
|
|
|
name.format = FontReader.ReadUInt16() |
|
|
|
|
name.count = FontReader.ReadUInt16() |
|
|
|
|
name.stringOffset = FontReader.ReadUInt16() |
|
|
|
|
|
|
|
|
|
for (i in 0 until name.count.toInt()) { |
|
|
|
|
val record = NameRecord() |
|
|
|
@ -271,54 +272,54 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
record.nameID = FontReader.ReadUInt16() |
|
|
|
|
record.length = FontReader.ReadUInt16() |
|
|
|
|
record.offset = FontReader.ReadUInt16() |
|
|
|
|
name.records.add(record); |
|
|
|
|
name.records.add(record) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 解析表 head (获取 head.indexToLocFormat) |
|
|
|
|
for (Temp in directorys) { |
|
|
|
|
if (Temp.tag == "head") { |
|
|
|
|
FontReader.Index = Temp.offset.toInt(); |
|
|
|
|
head.majorVersion = FontReader.ReadUInt16(); |
|
|
|
|
head.minorVersion = FontReader.ReadUInt16(); |
|
|
|
|
head.fontRevision = FontReader.ReadUInt32(); |
|
|
|
|
head.checkSumAdjustment = FontReader.ReadUInt32(); |
|
|
|
|
head.magicNumber = FontReader.ReadUInt32(); |
|
|
|
|
head.flags = FontReader.ReadUInt16(); |
|
|
|
|
head.unitsPerEm = FontReader.ReadUInt16(); |
|
|
|
|
head.created = FontReader.ReadUInt64(); |
|
|
|
|
head.modified = FontReader.ReadUInt64(); |
|
|
|
|
head.xMin = FontReader.ReadInt16(); |
|
|
|
|
head.yMin = FontReader.ReadInt16(); |
|
|
|
|
head.xMax = FontReader.ReadInt16(); |
|
|
|
|
head.yMax = FontReader.ReadInt16(); |
|
|
|
|
head.macStyle = FontReader.ReadUInt16(); |
|
|
|
|
head.lowestRecPPEM = FontReader.ReadUInt16(); |
|
|
|
|
head.fontDirectionHint = FontReader.ReadInt16(); |
|
|
|
|
head.indexToLocFormat = FontReader.ReadInt16(); |
|
|
|
|
head.glyphDataFormat = FontReader.ReadInt16(); |
|
|
|
|
FontReader.Index = Temp.offset.toInt() |
|
|
|
|
head.majorVersion = FontReader.ReadUInt16() |
|
|
|
|
head.minorVersion = FontReader.ReadUInt16() |
|
|
|
|
head.fontRevision = FontReader.ReadUInt32() |
|
|
|
|
head.checkSumAdjustment = FontReader.ReadUInt32() |
|
|
|
|
head.magicNumber = FontReader.ReadUInt32() |
|
|
|
|
head.flags = FontReader.ReadUInt16() |
|
|
|
|
head.unitsPerEm = FontReader.ReadUInt16() |
|
|
|
|
head.created = FontReader.ReadUInt64() |
|
|
|
|
head.modified = FontReader.ReadUInt64() |
|
|
|
|
head.xMin = FontReader.ReadInt16() |
|
|
|
|
head.yMin = FontReader.ReadInt16() |
|
|
|
|
head.xMax = FontReader.ReadInt16() |
|
|
|
|
head.yMax = FontReader.ReadInt16() |
|
|
|
|
head.macStyle = FontReader.ReadUInt16() |
|
|
|
|
head.lowestRecPPEM = FontReader.ReadUInt16() |
|
|
|
|
head.fontDirectionHint = FontReader.ReadInt16() |
|
|
|
|
head.indexToLocFormat = FontReader.ReadInt16() |
|
|
|
|
head.glyphDataFormat = FontReader.ReadInt16() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 解析表 maxp (获取 maxp.numGlyphs) |
|
|
|
|
for (Temp in directorys) { |
|
|
|
|
if (Temp.tag == "maxp") { |
|
|
|
|
FontReader.Index = Temp.offset.toInt(); |
|
|
|
|
maxp.majorVersion = FontReader.ReadUInt16(); |
|
|
|
|
maxp.minorVersion = FontReader.ReadUInt16(); |
|
|
|
|
maxp.numGlyphs = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxPoints = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxContours = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxCompositePoints = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxCompositeContours = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxZones = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxTwilightPoints = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxStorage = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxFunctionDefs = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxInstructionDefs = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxStackElements = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxSizeOfInstructions = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxComponentElements = FontReader.ReadUInt16(); |
|
|
|
|
maxp.maxComponentDepth = FontReader.ReadUInt16(); |
|
|
|
|
FontReader.Index = Temp.offset.toInt() |
|
|
|
|
maxp.majorVersion = FontReader.ReadUInt16() |
|
|
|
|
maxp.minorVersion = FontReader.ReadUInt16() |
|
|
|
|
maxp.numGlyphs = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxPoints = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxContours = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxCompositePoints = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxCompositeContours = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxZones = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxTwilightPoints = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxStorage = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxFunctionDefs = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxInstructionDefs = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxStackElements = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxSizeOfInstructions = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxComponentElements = FontReader.ReadUInt16() |
|
|
|
|
maxp.maxComponentDepth = FontReader.ReadUInt16() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 解析表 loca (轮廓数据偏移地址表) |
|
|
|
@ -348,13 +349,13 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
cmap.records.add(record) |
|
|
|
|
} |
|
|
|
|
for (i in 0 until cmap.numTables.toInt()) { |
|
|
|
|
val fmtOffset = cmap.records[i].offset; |
|
|
|
|
FontReader.Index = (Temp.offset + fmtOffset).toInt(); |
|
|
|
|
val EndIndex = FontReader.Index; |
|
|
|
|
val fmtOffset = cmap.records[i].offset |
|
|
|
|
FontReader.Index = (Temp.offset + fmtOffset).toInt() |
|
|
|
|
val EndIndex = FontReader.Index |
|
|
|
|
|
|
|
|
|
val format = FontReader.ReadUInt16(); |
|
|
|
|
val format = FontReader.ReadUInt16() |
|
|
|
|
|
|
|
|
|
if (cmap.tables.contains(fmtOffset.toInt())) continue; |
|
|
|
|
if (cmap.tables.contains(fmtOffset.toInt())) continue |
|
|
|
|
when { |
|
|
|
|
format.equals(0) -> { |
|
|
|
|
val fmt = CmapFormat0() |
|
|
|
@ -395,10 +396,10 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
format.equals(12) -> { |
|
|
|
|
val fmt = CmapFormat12() |
|
|
|
|
fmt.format = format |
|
|
|
|
fmt.reserved = FontReader.ReadUInt16(); |
|
|
|
|
fmt.length = FontReader.ReadUInt32(); |
|
|
|
|
fmt.language = FontReader.ReadUInt32(); |
|
|
|
|
fmt.numGroups = FontReader.ReadUInt32(); |
|
|
|
|
fmt.reserved = FontReader.ReadUInt16() |
|
|
|
|
fmt.length = FontReader.ReadUInt32() |
|
|
|
|
fmt.language = FontReader.ReadUInt32() |
|
|
|
|
fmt.numGroups = FontReader.ReadUInt32() |
|
|
|
|
for (n in 0 until fmt.numGroups.toLong()) { |
|
|
|
|
fmt.groups.add(Triple(FontReader.ReadUInt32(), FontReader.ReadUInt32(), FontReader.ReadUInt32())) |
|
|
|
|
} |
|
|
|
@ -430,7 +431,7 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
g.flags = ArrayList(flagLength) |
|
|
|
|
var n = 0 |
|
|
|
|
while (n < flagLength) { |
|
|
|
|
g.flags[n] = FontReader.GetByte(); |
|
|
|
|
g.flags[n] = FontReader.GetByte() |
|
|
|
|
if ((g.flags[n].and(0x08)).toInt() != 0x00) { |
|
|
|
|
for (m in FontReader.GetByte() downTo 1) { |
|
|
|
|
g.flags[++n] = g.flags[n - 1] |
|
|
|
@ -462,12 +463,12 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
// 相对坐标转绝对坐标 (因不绘制字体,这里用不上) |
|
|
|
|
for(m in 1 until flagLength) |
|
|
|
|
{ |
|
|
|
|
g.xCoordinates[m] = (g.xCoordinates[m] + g.xCoordinates[m - 1]).toShort(); |
|
|
|
|
g.yCoordinates[m] = (g.yCoordinates[m] + g.yCoordinates[m - 1]).toShort(); |
|
|
|
|
g.xCoordinates[m] = (g.xCoordinates[m] + g.xCoordinates[m - 1]).toShort() |
|
|
|
|
g.yCoordinates[m] = (g.yCoordinates[m] + g.yCoordinates[m - 1]).toShort() |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
glyf.add(g); |
|
|
|
|
glyf.add(g) |
|
|
|
|
} else { |
|
|
|
|
// 复合字体暂未使用 |
|
|
|
|
} |
|
|
|
@ -478,12 +479,12 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
// 建立Unicode&Glyf映射表 |
|
|
|
|
for (i in 0..130000) { |
|
|
|
|
val gid = GetGlyfIndex(i).toInt() |
|
|
|
|
if (gid == 0) continue; |
|
|
|
|
if (gid == 0) continue |
|
|
|
|
if (unicodeMap.containsKey(gid)) continue |
|
|
|
|
val thisGlyf = ArrayList<Short>() |
|
|
|
|
thisGlyf.addAll(glyf[gid].xCoordinates) |
|
|
|
|
thisGlyf.addAll(glyf[gid].yCoordinates) |
|
|
|
|
unicodeMap[i] = thisGlyf; |
|
|
|
|
unicodeMap[i] = thisGlyf |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
@ -494,76 +495,78 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
*/ |
|
|
|
|
fun GetNameById(nameId: Int = 1): String { |
|
|
|
|
for (Temp in directorys) { |
|
|
|
|
if (Temp.tag != "name") continue; |
|
|
|
|
FontReader.Index = Temp.offset.toInt(); |
|
|
|
|
break; |
|
|
|
|
if (Temp.tag != "name") continue |
|
|
|
|
FontReader.Index = Temp.offset.toInt() |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
for (record in name.records) { |
|
|
|
|
if (record.nameID.toInt() != nameId) continue; |
|
|
|
|
FontReader.Index = FontReader.Index + (name.stringOffset + record.offset).toInt(); |
|
|
|
|
return FontReader.ReadStrings(record.length.toInt(), if (record.platformID.toInt() == 1) Charsets.UTF_8 else Charsets.UTF_16BE); |
|
|
|
|
if (record.nameID.toInt() != nameId) continue |
|
|
|
|
FontReader.Index = FontReader.Index + (name.stringOffset + record.offset).toInt() |
|
|
|
|
return FontReader.ReadStrings(record.length.toInt(), if (record.platformID.toInt() == 1) Charsets.UTF_8 else Charsets.UTF_16BE) |
|
|
|
|
} |
|
|
|
|
return "error"; |
|
|
|
|
return "error" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var pps = arrayListOf<Pair<UShort, UShort>>(Pair(3u, 10u), Pair(0u, 4u), Pair(3u, 1u), Pair(1u, 0u), Pair(0u, 3u), Pair(0u, 1u)) |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 使用Unicode值查找轮廓索引 |
|
|
|
|
*/ |
|
|
|
|
private fun GetGlyfIndex(code: Int): Long { |
|
|
|
|
var fmtKey: UInt = 0u; |
|
|
|
|
for (record in cmap.records) { |
|
|
|
|
for (item in pps) { |
|
|
|
|
if (code == 0) return 0 |
|
|
|
|
var fmtKey: UInt = 0u |
|
|
|
|
for (item in pps) { |
|
|
|
|
for (record in cmap.records) { |
|
|
|
|
if ((item.first == record.platformID) && (item.second == record.encodingID)) { |
|
|
|
|
fmtKey = record.offset; |
|
|
|
|
break; |
|
|
|
|
fmtKey = record.offset |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (fmtKey > 0u) break; |
|
|
|
|
if (fmtKey > 0u) break |
|
|
|
|
} |
|
|
|
|
if (fmtKey == 0u) return 0; |
|
|
|
|
if (fmtKey == 0u) return 0 |
|
|
|
|
|
|
|
|
|
var glyfID: Long = 0; |
|
|
|
|
var glyfID: Long = 0 |
|
|
|
|
if (cmap.tables[fmtKey] is CmapFormat0) { |
|
|
|
|
val tab = cmap.tables[fmtKey] as CmapFormat0 |
|
|
|
|
if (code >= tab.glyphIdArray.size) glyfID = 0; |
|
|
|
|
else glyfID = tab.glyphIdArray[code].toLong(); |
|
|
|
|
if (code >= tab.glyphIdArray.size) glyfID = 0 |
|
|
|
|
else glyfID = tab.glyphIdArray[code].toLong() |
|
|
|
|
} else if (cmap.tables[fmtKey] is CmapFormat4) { |
|
|
|
|
val tab = cmap.tables[fmtKey] as CmapFormat4 |
|
|
|
|
if (code > tab.endCode.last().toInt()) return 0; |
|
|
|
|
if (code > tab.endCode.last().toInt()) return 0 |
|
|
|
|
// 二分法查找数值索引 |
|
|
|
|
var start = 0 |
|
|
|
|
var middle: Int |
|
|
|
|
var end = tab.endCode.size - 1; |
|
|
|
|
while (start + 1 != end) { |
|
|
|
|
middle = (start + end) / 2; |
|
|
|
|
if (tab.endCode[middle] <= code.toUInt()) start = middle; |
|
|
|
|
else end = middle; |
|
|
|
|
var end = tab.endCode.size - 1 |
|
|
|
|
while (start + 1 < end) { |
|
|
|
|
middle = (start + end) / 2 |
|
|
|
|
if (tab.endCode[middle] <= code.toUInt()) start = middle |
|
|
|
|
else end = middle |
|
|
|
|
} |
|
|
|
|
if (tab.endCode[start] < code.toUInt()) ++start; |
|
|
|
|
if (code.toUInt() < tab.startCode[start]) return 0; |
|
|
|
|
if (tab.endCode[start] < code.toUInt()) ++start |
|
|
|
|
if (code.toUInt() < tab.startCode[start]) return 0 |
|
|
|
|
glyfID = if (tab.idRangeOffset[start].toInt() != 0) { |
|
|
|
|
tab.glyphIdArray[code - tab.startCode[start].toInt() + (tab.idRangeOffset[start].toInt() / 2) - (tab.idRangeOffset.size - start)].toLong(); |
|
|
|
|
} else (code + tab.idDelta[start]).toLong(); |
|
|
|
|
tab.glyphIdArray[code - tab.startCode[start].toInt() + (tab.idRangeOffset[start].toInt() / 2) - (tab.idRangeOffset.size - start)].toLong() |
|
|
|
|
} else (code + tab.idDelta[start]).toLong() |
|
|
|
|
glyfID = glyfID.and(0xFFFF) |
|
|
|
|
} else if (cmap.tables[fmtKey] is CmapFormat6) { |
|
|
|
|
val tab = cmap.tables[fmtKey] as CmapFormat6 |
|
|
|
|
val index = code - tab.firstCode.toInt(); |
|
|
|
|
val index = code - tab.firstCode.toInt() |
|
|
|
|
glyfID = if (index < 0 || index >= tab.glyphIdArray.size) 0 else tab.glyphIdArray[index].toLong() |
|
|
|
|
} else if (cmap.tables[fmtKey] is CmapFormat12) { |
|
|
|
|
val tab = (cmap.tables[fmtKey] as CmapFormat12); |
|
|
|
|
if (code > tab.groups.last().second.toInt()) return 0; |
|
|
|
|
val tab = (cmap.tables[fmtKey] as CmapFormat12) |
|
|
|
|
if (code > tab.groups.last().second.toInt()) return 0 |
|
|
|
|
// 二分法查找数值索引 |
|
|
|
|
var start = 0 |
|
|
|
|
var middle: Int |
|
|
|
|
var end = tab.groups.size - 1; |
|
|
|
|
while (start + 1 != end) { |
|
|
|
|
middle = (start + end) / 2; |
|
|
|
|
if (tab.groups[middle].first.toInt() <= code) start = middle; |
|
|
|
|
else end = middle; |
|
|
|
|
var end = tab.groups.size - 1 |
|
|
|
|
while (start + 1 < end) { |
|
|
|
|
middle = (start + end) / 2 |
|
|
|
|
if (tab.groups[middle].first.toInt() <= code) start = middle |
|
|
|
|
else end = middle |
|
|
|
|
} |
|
|
|
|
if (tab.groups[start].first.toInt() <= code && code <= tab.groups[start].second.toInt()) { |
|
|
|
|
glyfID = (tab.groups[start].third.toInt() + code - tab.groups[start].first.toInt()).toLong(); |
|
|
|
|
glyfID = (tab.groups[start].third.toInt() + code - tab.groups[start].first.toInt()).toLong() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return glyfID |
|
|
|
@ -572,31 +575,28 @@ class QueryTTF(var Font: ByteArray) : JsExtensions { |
|
|
|
|
/** |
|
|
|
|
* 使用轮廓数据获取Unicode值 |
|
|
|
|
*/ |
|
|
|
|
public fun GetCodeByGlyf(inputGlyf:List<Short>): Int { |
|
|
|
|
var unicodeVal = 0; |
|
|
|
|
if(inputGlyf.isEmpty()) return 0; |
|
|
|
|
for(g in unicodeMap) |
|
|
|
|
{ |
|
|
|
|
if (inputGlyf.size != g.value.size) continue; |
|
|
|
|
var isFound = true; |
|
|
|
|
for(i in inputGlyf.indices) |
|
|
|
|
{ |
|
|
|
|
public fun GetCodeByGlyf(inputGlyf: List<Short>): Int { |
|
|
|
|
var unicodeVal = 0 |
|
|
|
|
if (inputGlyf.isEmpty()) return 0 |
|
|
|
|
for (g in unicodeMap) { |
|
|
|
|
if (inputGlyf.size != g.value.size) continue |
|
|
|
|
var isFound = true |
|
|
|
|
for (i in inputGlyf.indices) { |
|
|
|
|
if (inputGlyf[i] != g.value[i]) { |
|
|
|
|
isFound = false; |
|
|
|
|
break; |
|
|
|
|
isFound = false |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (isFound) unicodeVal = g.key; |
|
|
|
|
if (isFound) unicodeVal = g.key |
|
|
|
|
} |
|
|
|
|
return unicodeVal; |
|
|
|
|
return unicodeVal |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 使用Unicode值获取轮廓数据 |
|
|
|
|
*/ |
|
|
|
|
public fun GetGlyfByCode(code:Int): ArrayList<Short> |
|
|
|
|
{ |
|
|
|
|
if(code <= 0) return ArrayList() |
|
|
|
|
public fun GetGlyfByCode(code: Int): ArrayList<Short> { |
|
|
|
|
if (code <= 0) return ArrayList() |
|
|
|
|
return unicodeMap.getOrDefault(code, ArrayList()) |
|
|
|
|
} |
|
|
|
|
} |