pull/487/head^2
gedoor 5 years ago
parent 21ff748eb2
commit bfe8b68004
  1. 87
      app/src/main/java/io/legado/app/model/analyzeRule/QueryTTF.kt

@ -3,12 +3,13 @@ package io.legado.app.model.analyzeRule
import io.legado.app.help.JsExtensions import io.legado.app.help.JsExtensions
import kotlin.experimental.and import kotlin.experimental.and
@ExperimentalUnsignedTypes
/** /**
* 解析TTF字体 * 解析TTF字体
* @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>
*/ */
@Suppress("unused", "RedundantExplicitType", "MemberVisibilityCanBePrivate")
@ExperimentalUnsignedTypes
class QueryTTF(var font: ByteArray) : JsExtensions { class QueryTTF(var font: ByteArray) : JsExtensions {
data class Index(var num: Int) data class Index(var num: Int)
@ -33,7 +34,7 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
var format: UShort = 0u var format: UShort = 0u
var count: UShort = 0u var count: UShort = 0u
var stringOffset: UShort = 0u var stringOffset: UShort = 0u
var Records = ArrayList<NameRecord>() var records = ArrayList<NameRecord>()
} }
class NameRecord { class NameRecord {
@ -136,9 +137,9 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
lateinit var yCoordinates: Array<Short> lateinit var yCoordinates: Array<Short>
} }
var Header = FileHeader() var header = FileHeader()
var Tables = mutableMapOf<String, TableDirectory>() var tables = mutableMapOf<String, TableDirectory>()
var name = NameTable() var name = NameTable()
@ -165,7 +166,7 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
} }
// 索引变量 // 索引变量
var index = 0 private var index = 0
// 从索引index开始拷贝指定长度的数组 // 从索引index开始拷贝指定长度的数组
private fun ByteArray.copyOfIndex(length: Int): ByteArray { private fun ByteArray.copyOfIndex(length: Int): ByteArray {
@ -182,26 +183,26 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
init { init {
// 解析文件头 // 解析文件头
Header = FileHeader() header = FileHeader()
// 跳过不需要的数据条目 // 跳过不需要的数据条目
index = 4 index = 4
Header.numOfTables = byteArrToUintx(font.copyOfIndex(2)).toUShort() header.numOfTables = byteArrToUintx(font.copyOfIndex(2)).toUShort()
// 获取数据表 // 获取数据表
index = 12 index = 12
for (i in 0 until Header.numOfTables.toInt()) { for (i in 0 until header.numOfTables.toInt()) {
val table = TableDirectory() val table = TableDirectory()
table.tag = font.copyOfIndex(4).toString(Charsets.US_ASCII) table.tag = font.copyOfIndex(4).toString(Charsets.US_ASCII)
table.checkSum = byteArrToUintx(font.copyOfIndex(4)).toUInt() table.checkSum = byteArrToUintx(font.copyOfIndex(4)).toUInt()
table.offset = byteArrToUintx(font.copyOfIndex(4)).toUInt() table.offset = byteArrToUintx(font.copyOfIndex(4)).toUInt()
table.length = byteArrToUintx(font.copyOfIndex(4)).toUInt() table.length = byteArrToUintx(font.copyOfIndex(4)).toUInt()
table.data = font.copyOfIndex(table.offset.toInt(), table.length.toInt()) table.data = font.copyOfIndex(table.offset.toInt(), table.length.toInt())
Tables[table.tag] = table tables[table.tag] = table
} }
// 解析表 name (字体信息,包含版权、名称、作者等...) // 解析表 name (字体信息,包含版权、名称、作者等...)
run { run {
val data = Tables["name"]!!.data val data = tables["name"]!!.data
index = 0 index = 0
name.format = byteArrToUintx(data.copyOfIndex(2)).toUShort() name.format = byteArrToUintx(data.copyOfIndex(2)).toUShort()
name.count = byteArrToUintx(data.copyOfIndex(2)).toUShort() name.count = byteArrToUintx(data.copyOfIndex(2)).toUShort()
@ -215,14 +216,17 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
record.nameID = byteArrToUintx(data.copyOfIndex(2)).toUShort() record.nameID = byteArrToUintx(data.copyOfIndex(2)).toUShort()
record.length = byteArrToUintx(data.copyOfIndex(2)).toUShort() record.length = byteArrToUintx(data.copyOfIndex(2)).toUShort()
record.offset = byteArrToUintx(data.copyOfIndex(2)).toUShort() record.offset = byteArrToUintx(data.copyOfIndex(2)).toUShort()
record.nameBuffer = data.copyOfIndex((name.stringOffset + record.offset).toInt(), record.length.toInt()) record.nameBuffer = data.copyOfIndex(
name.Records.add(record) (name.stringOffset + record.offset).toInt(),
record.length.toInt()
)
name.records.add(record)
} }
} }
// 解析表 head (获取 head.indexToLocFormat) // 解析表 head (获取 head.indexToLocFormat)
run { run {
val data = Tables["head"]!!.data val data = tables["head"]!!.data
index = 0 index = 0
head.majorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort() head.majorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort()
head.minorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort() head.minorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort()
@ -246,8 +250,7 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
// 解析表 maxp (获取 maxp.numGlyphs) // 解析表 maxp (获取 maxp.numGlyphs)
run { run {
val data = Tables["maxp"]!!.data val data = tables["maxp"]!!.data
index = 0
index = 0 index = 0
maxp.majorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort() maxp.majorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort()
maxp.minorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort() maxp.minorVersion = byteArrToUintx(data.copyOfIndex(2)).toUShort()
@ -269,7 +272,7 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
// 解析表 loca (轮廓数据偏移地址表) // 解析表 loca (轮廓数据偏移地址表)
run { run {
val data = Tables["maxp"]!!.data val data = tables["maxp"]!!.data
val offset = if (head.indexToLocFormat.equals(0)) 2 else 4 val offset = if (head.indexToLocFormat.equals(0)) 2 else 4
index = 0 index = 0
while (index < data.size) { while (index < data.size) {
@ -280,7 +283,7 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
// 解析表 cmap (Unicode编码轮廓索引对照表) // 解析表 cmap (Unicode编码轮廓索引对照表)
run { run {
val data = Tables["cmap"]!!.data val data = tables["cmap"]!!.data
index = 0 index = 0
cmap.version = byteArrToUintx(data.copyOfIndex(2)).toUShort() cmap.version = byteArrToUintx(data.copyOfIndex(2)).toUShort()
cmap.numTables = byteArrToUintx(data.copyOfIndex(2)).toUShort() cmap.numTables = byteArrToUintx(data.copyOfIndex(2)).toUShort()
@ -291,7 +294,7 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
record.encodingID = byteArrToUintx(data.copyOfIndex(2)).toUShort() record.encodingID = byteArrToUintx(data.copyOfIndex(2)).toUShort()
record.offset = byteArrToUintx(data.copyOfIndex(4)).toUInt() record.offset = byteArrToUintx(data.copyOfIndex(4)).toUInt()
cmap.records.add(record) cmap.records.add(record)
val tmpIndex = index; // 缓存索引 val tmpIndex = index // 缓存索引
index = record.offset.toInt() index = record.offset.toInt()
val fmt = byteArrToUintx(data.copyOfIndex(2)).toUShort() val fmt = byteArrToUintx(data.copyOfIndex(2)).toUShort()
@ -336,13 +339,13 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
} }
cmap.tables[fmt.toInt()] = ft cmap.tables[fmt.toInt()] = ft
} }
index = tmpIndex; // 读取缓存的索引 index = tmpIndex // 读取缓存的索引
} }
} }
// 解析表 glyf (字体轮廓数据表) // 解析表 glyf (字体轮廓数据表)
run { run {
val data = Tables["glyf"]!!.data val data = tables["glyf"]!!.data
for (i in 0 until maxp.numGlyphs.toInt()) { for (i in 0 until maxp.numGlyphs.toInt()) {
index = loca[i].toInt() index = loca[i].toInt()
val numberOfContours = byteArrToUintx(data.copyOfIndex(2)).toShort() val numberOfContours = byteArrToUintx(data.copyOfIndex(2)).toShort()
@ -359,9 +362,11 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
g.yMax = yMax g.yMax = yMax
g.endPtsOfContours = IntArray(numberOfContours.toInt()) g.endPtsOfContours = IntArray(numberOfContours.toInt())
for (n in 0 until numberOfContours) { for (n in 0 until numberOfContours) {
g.endPtsOfContours[n] = byteArrToUintx(data.copyOfIndex(2)).toInt(); // 这里数据源为UShort g.endPtsOfContours[n] =
byteArrToUintx(data.copyOfIndex(2)).toInt() // 这里数据源为UShort
} }
g.instructionLength = byteArrToUintx(data.copyOfIndex(2)).toInt(); // 这里数据源为UShort g.instructionLength =
byteArrToUintx(data.copyOfIndex(2)).toInt() // 这里数据源为UShort
g.instructions = data.copyOfIndex(g.instructionLength) g.instructions = data.copyOfIndex(g.instructionLength)
val flagLength = g.endPtsOfContours.last() + 1 val flagLength = g.endPtsOfContours.last() + 1
g.flags = ByteArray(flagLength) g.flags = ByteArray(flagLength)
@ -384,7 +389,8 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
val xByte = !(g.flags[n] and 0x02).equals(0) val xByte = !(g.flags[n] and 0x02).equals(0)
val xSame = !(g.flags[n] and 0x10).equals(0) val xSame = !(g.flags[n] and 0x10).equals(0)
if (xByte) { if (xByte) {
g.xCoordinates[n] = ((if (xSame) 1 else -1) * data.copyOfIndex(1).first()).toShort() g.xCoordinates[n] =
((if (xSame) 1 else -1) * data.copyOfIndex(1).first()).toShort()
} else { } else {
if (xSame) g.xCoordinates[n] = 0 if (xSame) g.xCoordinates[n] = 0
else { else {
@ -398,7 +404,8 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
val yByte = !(g.flags[n] and 0x04).equals(0) val yByte = !(g.flags[n] and 0x04).equals(0)
val ySame = !(g.flags[n] and 0x20).equals(0) val ySame = !(g.flags[n] and 0x20).equals(0)
if (yByte) { if (yByte) {
g.yCoordinates[n] = ((if (ySame) 1 else -1) * data.copyOfIndex(1).first()).toShort() g.yCoordinates[n] =
((if (ySame) 1 else -1) * data.copyOfIndex(1).first()).toShort()
} else { } else {
if (ySame) g.yCoordinates[n] = 0 if (ySame) g.yCoordinates[n] = 0
else { else {
@ -427,8 +434,8 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
* 获取字体信息默认获取字体名称 * 获取字体信息默认获取字体名称
* @see <a href="https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids">获取详情</a> * @see <a href="https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids">获取详情</a>
*/ */
fun GetName(nameID: Int = 1): String { fun getName(nameID: Int = 1): String {
for (record in name.Records) { for (record in name.records) {
if (!record.nameID.equals(nameID)) continue if (!record.nameID.equals(nameID)) continue
if (record.platformID.equals(1) && record.encodingID.equals(0)) { if (record.platformID.equals(1) && record.encodingID.equals(0)) {
return record.nameBuffer.toString(Charsets.UTF_8) return record.nameBuffer.toString(Charsets.UTF_8)
@ -440,10 +447,10 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
} }
/** /**
* 获取字体轮廓 (fontCode:十进制Unicode字符编码) * 获取字体轮廓 (fontCode:十进制Unicode字符编码)
*/ */
fun GetGlyf(fontCode: Int): ArrayList<Short> { fun getGlyf(fontCode: Int): ArrayList<Short> {
var fontIndex = -1; // 轮廓索引 var fontIndex = -1 // 轮廓索引
val fmt4 = cmap.tables.getOrDefault(4, null) val fmt4 = cmap.tables.getOrDefault(4, null)
if (fmt4 != null) { if (fmt4 != null) {
val fmt = (fmt4 as Format4) val fmt = (fmt4 as Format4)
@ -454,14 +461,18 @@ class QueryTTF(var font: ByteArray) : JsExtensions {
break break
} }
} }
if (fontIndex == -1) fontIndex = 0 when {
else if (fontCode < fmt.startCode[fontIndex]) fontIndex = 0 fontIndex == -1 -> fontIndex = 0
else { fontCode < fmt.startCode[fontIndex] -> fontIndex = 0
if (fmt.idRangeOffset[fontIndex] != 0) { else -> {
fontIndex = fontIndex = if (fmt.idRangeOffset[fontIndex] != 0) {
fmt.glyphIdArray[fontCode - fmt.startCode[fontIndex] + fmt.idRangeOffset[fontIndex].ushr(1) - (fmt.idRangeOffset.size - fontIndex)].toInt() val i = (fontCode - fmt.startCode[fontIndex]
} else fontIndex = fontCode + fmt.idDelta[fontIndex] + fmt.idRangeOffset[fontIndex].ushr(1)
fontIndex = fontIndex and 0xFFFF - (fmt.idRangeOffset.size - fontIndex))
fmt.glyphIdArray[i].toInt()
} else fontCode + fmt.idDelta[fontIndex]
fontIndex = fontIndex and 0xFFFF
}
} }
} else { } else {
val fmt0 = cmap.tables.getOrDefault(0, null) val fmt0 = cmap.tables.getOrDefault(0, null)

Loading…
Cancel
Save