修复编码索引顺序错误的BUG

pull/489/head
Antecer 4 years ago
parent bd28708c0f
commit e7a63c68eb
  1. 242
      app/src/main/java/io/legado/app/model/analyzeRule/QueryTTF.kt

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