diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/QueryTTF.java b/app/src/main/java/io/legado/app/model/analyzeRule/QueryTTF.java index c87249cdc..26bd4cb83 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/QueryTTF.java +++ b/app/src/main/java/io/legado/app/model/analyzeRule/QueryTTF.java @@ -1,17 +1,21 @@ package io.legado.app.model.analyzeRule; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; +import android.util.Log; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.HashMap; +import java.util.Map; +import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; -import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; -@SuppressWarnings({"FieldCanBeLocal", "unused"}) +@SuppressWarnings({"FieldCanBeLocal", "StatementWithEmptyBody", "unused"}) public class QueryTTF { private static class Header { public int majorVersion; @@ -129,7 +133,7 @@ public class QueryTTF { public int length; public int language; public int numGroups; - public List> groups; + public List groups; } private static class GlyfLayout { @@ -147,103 +151,313 @@ public class QueryTTF { } private static class ByteArrayReader { - public int index; - public byte[] buffer; + private final byte[] buffer; + public final ByteBuffer byteBuffer; public ByteArrayReader(byte[] buffer, int index) { this.buffer = buffer; - this.index = index; + this.byteBuffer = ByteBuffer.wrap(buffer); + this.byteBuffer.order(ByteOrder.BIG_ENDIAN); // 设置为大端模式 + this.byteBuffer.position(index); // 设置起始索引 } - public long ReadUIntX(long len) { - long result = 0; - for (long i = 0; i < len; ++i) { - result <<= 8; - result |= buffer[index++] & 0xFF; - } - return result; + public void position(int index) { + byteBuffer.position(index); // 设置起始索引 } + public int position() { + return byteBuffer.position(); + } + + public long ReadUInt64() { - return ReadUIntX(8); + return byteBuffer.getLong(); } public int ReadUInt32() { - return (int) ReadUIntX(4); + return byteBuffer.getInt(); + } + + public int ReadInt32() { + return byteBuffer.getInt(); } public int ReadUInt16() { - return (int) ReadUIntX(2); + return byteBuffer.getShort() & 0xFFFF; } public short ReadInt16() { - return (short) ReadUIntX(2); + return byteBuffer.getShort(); } public short ReadUInt8() { - return (short) ReadUIntX(1); + return (short) (byteBuffer.get() & 0xFF); } - - public String ReadStrings(int len, Charset charset) { - byte[] result = len > 0 ? new byte[len] : null; - for (int i = 0; i < len; ++i) result[i] = buffer[index++]; - return new String(result, charset); + public byte ReadInt8() { + return byteBuffer.get(); } - public byte GetByte() { - return buffer[index++]; - } - - public byte[] GetBytes(int len) { - byte[] result = len > 0 ? new byte[len] : null; - for (int i = 0; i < len; ++i) result[i] = buffer[index++]; + public byte[] ReadByteArray(int len) { + if (len < 0) throw new IllegalArgumentException("Length must not be negative"); + byte[] result = new byte[len]; + byteBuffer.get(result); return result; } - public int[] GetUInt16Array(int len) { - int[] result = len > 0 ? new int[len] : null; - for (int i = 0; i < len; ++i) result[i] = ReadUInt16(); + public short[] ReadInt16Array(int len) { + if (len < 0) throw new IllegalArgumentException("Length must not be negative"); + var result = new short[len]; + for (int i = 0; i < len; ++i) result[i] = byteBuffer.getShort(); return result; } - public short[] GetInt16Array(int len) { - short[] result = len > 0 ? new short[len] : null; - for (int i = 0; i < len; ++i) result[i] = ReadInt16(); + public int[] ReadUInt16Array(int len) { + if (len < 0) throw new IllegalArgumentException("Length must not be negative"); + var result = new int[len]; + for (int i = 0; i < len; ++i) result[i] = byteBuffer.getShort() & 0xFFFF; return result; } } - private final ByteArrayReader fontReader; private final Header fileHeader = new Header(); - private final List directorys = new LinkedList<>(); + private final Map directorys = new HashMap<>(); private final NameLayout name = new NameLayout(); private final HeadLayout head = new HeadLayout(); private final MaxpLayout maxp = new MaxpLayout(); private final List loca = new LinkedList<>(); private final CmapLayout Cmap = new CmapLayout(); - private final List glyf = new LinkedList<>(); - @SuppressWarnings("unchecked") - private final Pair[] pps = new Pair[]{ - Pair.of(3, 10), - Pair.of(0, 4), - Pair.of(3, 1), - Pair.of(1, 0), - Pair.of(0, 3), - Pair.of(0, 1) + private final ConcurrentHashMap glyf = new ConcurrentHashMap<>(); + private final int[][] pps = new int[][]{ + {3, 10}, + {0, 4}, + {3, 1}, + {1, 0}, + {0, 3}, + {0, 1} }; public final Map unicodeToGlyph = new HashMap<>(); public final Map glyphToUnicode = new HashMap<>(); public final Map unicodeToGlyphIndex = new HashMap<>(); + private void readNameTable(byte[] buffer) { + var dataTable = Objects.requireNonNull(directorys.get("name")); + var reader = new ByteArrayReader(buffer, dataTable.offset); + name.format = reader.ReadUInt16(); + name.count = reader.ReadUInt16(); + name.stringOffset = reader.ReadUInt16(); + for (int i = 0; i < name.count; ++i) { + NameRecord record = new NameRecord(); + record.platformID = reader.ReadUInt16(); + record.encodingID = reader.ReadUInt16(); + record.languageID = reader.ReadUInt16(); + record.nameID = reader.ReadUInt16(); + record.length = reader.ReadUInt16(); + record.offset = reader.ReadUInt16(); + name.records.add(record); + } + } + + private void readHeadTable(byte[] buffer) { + var dataTable = Objects.requireNonNull(directorys.get("head")); + var reader = new ByteArrayReader(buffer, dataTable.offset); + head.majorVersion = reader.ReadUInt16(); + head.minorVersion = reader.ReadUInt16(); + head.fontRevision = reader.ReadUInt32(); + head.checkSumAdjustment = reader.ReadUInt32(); + head.magicNumber = reader.ReadUInt32(); + head.flags = reader.ReadUInt16(); + head.unitsPerEm = reader.ReadUInt16(); + head.created = reader.ReadUInt64(); + head.modified = reader.ReadUInt64(); + head.xMin = reader.ReadInt16(); + head.yMin = reader.ReadInt16(); + head.xMax = reader.ReadInt16(); + head.yMax = reader.ReadInt16(); + head.macStyle = reader.ReadUInt16(); + head.lowestRecPPEM = reader.ReadUInt16(); + head.fontDirectionHint = reader.ReadInt16(); + head.indexToLocFormat = reader.ReadInt16(); + head.glyphDataFormat = reader.ReadInt16(); + } + + private void readCmapTable(byte[] buffer) { + var dataTable = Objects.requireNonNull(directorys.get("cmap")); + var reader = new ByteArrayReader(buffer, dataTable.offset); + Cmap.version = reader.ReadUInt16(); + Cmap.numTables = reader.ReadUInt16(); + for (int i = 0; i < Cmap.numTables; ++i) { + CmapRecord record = new CmapRecord(); + record.platformID = reader.ReadUInt16(); + record.encodingID = reader.ReadUInt16(); + record.offset = reader.ReadUInt32(); + Cmap.records.add(record); + } + for (int i = 0; i < Cmap.numTables; ++i) { + int fmtOffset = Cmap.records.get(i).offset; + reader.position(dataTable.offset + fmtOffset); + int EndIndex = reader.position(); + + int format = reader.ReadUInt16(); + if (Cmap.tables.containsKey(fmtOffset)) continue; + if (format == 0) { + CmapFormat f = new CmapFormat(); + f.format = format; + f.length = reader.ReadUInt16(); + f.language = reader.ReadUInt16(); + f.glyphIdArray = reader.ReadByteArray(f.length - 6); + Cmap.tables.put(fmtOffset, f); + } else if (format == 4) { + CmapFormat4 f = new CmapFormat4(); + f.format = format; + f.length = reader.ReadUInt16(); + f.language = reader.ReadUInt16(); + f.segCountX2 = reader.ReadUInt16(); + int segCount = f.segCountX2 >> 1; + f.searchRange = reader.ReadUInt16(); + f.entrySelector = reader.ReadUInt16(); + f.rangeShift = reader.ReadUInt16(); + f.endCode = reader.ReadUInt16Array(segCount); + f.reservedPad = reader.ReadUInt16(); + f.startCode = reader.ReadUInt16Array(segCount); + f.idDelta = reader.ReadInt16Array(segCount); + f.idRangeOffset = reader.ReadUInt16Array(segCount); + f.glyphIdArray = reader.ReadUInt16Array((EndIndex + f.length - reader.position()) >> 1); + Cmap.tables.put(fmtOffset, f); + } else if (format == 6) { + CmapFormat6 f = new CmapFormat6(); + f.format = format; + f.length = reader.ReadUInt16(); + f.language = reader.ReadUInt16(); + f.firstCode = reader.ReadUInt16(); + f.entryCount = reader.ReadUInt16(); + f.glyphIdArray = reader.ReadUInt16Array(f.entryCount); + Cmap.tables.put(fmtOffset, f); + } else if (format == 12) { + CmapFormat12 f = new CmapFormat12(); + f.format = format; + f.reserved = reader.ReadUInt16(); + f.length = reader.ReadUInt32(); + f.language = reader.ReadUInt32(); + f.numGroups = reader.ReadUInt32(); + f.groups = new LinkedList<>(); + for (int n = 0; n < f.numGroups; ++n) { + f.groups.add(new int[]{reader.ReadUInt32(), reader.ReadUInt32(), reader.ReadUInt32()}); + } + Cmap.tables.put(fmtOffset, f); + } + } + } + + private void readLocaTable(byte[] buffer) { + var dataTable = Objects.requireNonNull(directorys.get("loca")); + var reader = new ByteArrayReader(buffer, dataTable.offset); + var locaTableSize = dataTable.length; + if (head.indexToLocFormat == 0) { + for (long i = 0; i < locaTableSize; i += 2) loca.add(reader.ReadUInt16()); + } else { + for (long i = 0; i < locaTableSize; i += 4) loca.add(reader.ReadUInt32()); + } + } + + private void readMaxpTable(byte[] buffer) { + var dataTable = Objects.requireNonNull(directorys.get("maxp")); + var reader = new ByteArrayReader(buffer, dataTable.offset); + maxp.majorVersion = reader.ReadUInt16(); + maxp.minorVersion = reader.ReadUInt16(); + maxp.numGlyphs = reader.ReadUInt16(); + maxp.maxPoints = reader.ReadUInt16(); + maxp.maxContours = reader.ReadUInt16(); + maxp.maxCompositePoints = reader.ReadUInt16(); + maxp.maxCompositeContours = reader.ReadUInt16(); + maxp.maxZones = reader.ReadUInt16(); + maxp.maxTwilightPoints = reader.ReadUInt16(); + maxp.maxStorage = reader.ReadUInt16(); + maxp.maxFunctionDefs = reader.ReadUInt16(); + maxp.maxInstructionDefs = reader.ReadUInt16(); + maxp.maxStackElements = reader.ReadUInt16(); + maxp.maxSizeOfInstructions = reader.ReadUInt16(); + maxp.maxComponentElements = reader.ReadUInt16(); + maxp.maxComponentDepth = reader.ReadUInt16(); + } + + private void readGlyfTable(byte[] buffer) { + var dataTable = Objects.requireNonNull(directorys.get("glyf")); + int glyfCount = maxp.numGlyphs; + + ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + for (int i = 0; i < glyfCount; i++) { + final int index = i; + executor.submit(() -> { + var reader = new ByteArrayReader(buffer, dataTable.offset + loca.get(index)); + int glyfNextIndex = index + 1 < glyfCount ? (dataTable.offset + loca.get(index + 1)) : (dataTable.offset + dataTable.length); + byte[] glyph; + short numberOfContours = reader.ReadInt16(); + if (numberOfContours > 0) { + short g_xMin = reader.ReadInt16(); + short g_yMin = reader.ReadInt16(); + short g_xMax = reader.ReadInt16(); + short g_yMax = reader.ReadInt16(); + int[] endPtsOfContours = reader.ReadUInt16Array(numberOfContours); + int instructionLength = reader.ReadUInt16(); + var instructions = reader.ReadByteArray(instructionLength); + int flagLength = endPtsOfContours[endPtsOfContours.length - 1] + 1; + // 获取轮廓点描述标志 + var flags = new byte[flagLength]; + for (int n = 0; n < flagLength; ++n) { + flags[n] = reader.ReadInt8(); + if ((flags[n] & 0x08) != 0x00) { + for (int m = reader.ReadUInt8(); m > 0; --m) { + flags[++n] = flags[n - 1]; + } + } + } + // 获取轮廓点描述x,y相对值 + ByteBuffer xyCoordinatesBuffer = ByteBuffer.allocate(flagLength * 4); + // 获取轮廓点描述x轴相对值 + for (int n = 0; n < flagLength; ++n) { + short same = (short) ((flags[n] & 0x10) != 0 ? 1 : -1); + if ((flags[n] & 0x02) != 0) { + xyCoordinatesBuffer.putShort((short) (same * reader.ReadUInt8())); + } else { + xyCoordinatesBuffer.putShort(same == 1 ? (short) 0 : reader.ReadInt16()); + } + } + // 获取轮廓点描述y轴相对值 + for (int n = 0; n < flagLength; ++n) { + short same = (short) ((flags[n] & 0x20) != 0 ? 1 : -1); + if ((flags[n] & 0x04) != 0) { + xyCoordinatesBuffer.putShort((short) (same * reader.ReadUInt8())); + } else { + xyCoordinatesBuffer.putShort(same == 1 ? (short) 0 : reader.ReadInt16()); + } + } + // 保存轮廓点描述x,y相对值ByteArray + glyph = xyCoordinatesBuffer.array(); + } else { + // 复合字体未做详细处理 + glyph = reader.ReadByteArray(glyfNextIndex - (reader.position() - 2)); + } + glyf.put(index, getHexFromBytes(glyph)); + }); + } + executor.shutdown(); + try { + boolean b = executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Log.e("queryTTF", "glyf表解析出错: " + e); + } + } + /** * 构造函数 * * @param buffer 传入TTF字体二进制数组 */ public QueryTTF(byte[] buffer) { - fontReader = new ByteArrayReader(buffer, 0); + var fontReader = new ByteArrayReader(buffer, 0); + Log.i("[queryTTF]", "读文件头"); // 获取文件头 fileHeader.majorVersion = fontReader.ReadUInt16(); fileHeader.minorVersion = fontReader.ReadUInt16(); @@ -254,187 +468,29 @@ public class QueryTTF { // 获取目录 for (int i = 0; i < fileHeader.numOfTables; ++i) { Directory d = new Directory(); - d.tag = fontReader.ReadStrings(4, StandardCharsets.US_ASCII); + d.tag = new String(fontReader.ReadByteArray(4), StandardCharsets.US_ASCII); d.checkSum = fontReader.ReadUInt32(); d.offset = fontReader.ReadUInt32(); d.length = fontReader.ReadUInt32(); - directorys.add(d); - } - // 解析表 name (字体信息,包含版权、名称、作者等...) - for (Directory Temp : directorys) { - if (Temp.tag.equals("name")) { - fontReader.index = Temp.offset; - name.format = fontReader.ReadUInt16(); - name.count = fontReader.ReadUInt16(); - name.stringOffset = fontReader.ReadUInt16(); - for (int i = 0; i < name.count; ++i) { - NameRecord record = new NameRecord(); - record.platformID = fontReader.ReadUInt16(); - record.encodingID = fontReader.ReadUInt16(); - record.languageID = fontReader.ReadUInt16(); - record.nameID = fontReader.ReadUInt16(); - record.length = fontReader.ReadUInt16(); - record.offset = fontReader.ReadUInt16(); - name.records.add(record); - } - } - } - // 解析表 head (获取 head.indexToLocFormat) - for (Directory Temp : directorys) { - if (Temp.tag.equals("head")) { - fontReader.index = Temp.offset; - 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 (Directory Temp : directorys) { - if (Temp.tag.equals("maxp")) { - fontReader.index = Temp.offset; - 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 (轮廓数据偏移地址表) - for (Directory Temp : directorys) { - if (Temp.tag.equals("loca")) { - fontReader.index = Temp.offset; - int offset = head.indexToLocFormat == 0 ? 2 : 4; - for (long i = 0; i < Temp.length; i += offset) { - loca.add(offset == 2 ? fontReader.ReadUInt16() << 1 : fontReader.ReadUInt32()); - } - } - } - // 解析表 cmap (Unicode编码轮廓索引对照表) - for (Directory Temp : directorys) { - if (Temp.tag.equals("cmap")) { - fontReader.index = Temp.offset; - Cmap.version = fontReader.ReadUInt16(); - Cmap.numTables = fontReader.ReadUInt16(); - - for (int i = 0; i < Cmap.numTables; ++i) { - CmapRecord record = new CmapRecord(); - record.platformID = fontReader.ReadUInt16(); - record.encodingID = fontReader.ReadUInt16(); - record.offset = fontReader.ReadUInt32(); - Cmap.records.add(record); - } - for (int i = 0; i < Cmap.numTables; ++i) { - int fmtOffset = Cmap.records.get(i).offset; - fontReader.index = Temp.offset + fmtOffset; - int EndIndex = fontReader.index; - - int format = fontReader.ReadUInt16(); - if (Cmap.tables.containsKey(fmtOffset)) continue; - if (format == 0) { - CmapFormat f = new CmapFormat(); - f.format = format; - f.length = fontReader.ReadUInt16(); - f.language = fontReader.ReadUInt16(); - f.glyphIdArray = fontReader.GetBytes(f.length - 6); - Cmap.tables.put(fmtOffset, f); - } else if (format == 4) { - CmapFormat4 f = new CmapFormat4(); - f.format = format; - f.length = fontReader.ReadUInt16(); - f.language = fontReader.ReadUInt16(); - f.segCountX2 = fontReader.ReadUInt16(); - int segCount = f.segCountX2 >> 1; - f.searchRange = fontReader.ReadUInt16(); - f.entrySelector = fontReader.ReadUInt16(); - f.rangeShift = fontReader.ReadUInt16(); - f.endCode = fontReader.GetUInt16Array(segCount); - f.reservedPad = fontReader.ReadUInt16(); - f.startCode = fontReader.GetUInt16Array(segCount); - f.idDelta = fontReader.GetInt16Array(segCount); - f.idRangeOffset = fontReader.GetUInt16Array(segCount); - f.glyphIdArray = fontReader.GetUInt16Array((EndIndex + f.length - fontReader.index) >> 1); - Cmap.tables.put(fmtOffset, f); - } else if (format == 6) { - CmapFormat6 f = new CmapFormat6(); - f.format = format; - f.length = fontReader.ReadUInt16(); - f.language = fontReader.ReadUInt16(); - f.firstCode = fontReader.ReadUInt16(); - f.entryCount = fontReader.ReadUInt16(); - f.glyphIdArray = fontReader.GetUInt16Array(f.entryCount); - Cmap.tables.put(fmtOffset, f); - } else if (format == 12) { - CmapFormat12 f = new CmapFormat12(); - f.format = format; - f.reserved = fontReader.ReadUInt16(); - f.length = fontReader.ReadUInt32(); - f.language = fontReader.ReadUInt32(); - f.numGroups = fontReader.ReadUInt32(); - f.groups = new ArrayList<>(f.numGroups); - for (int n = 0; n < f.numGroups; ++n) { - f.groups.add(Triple.of(fontReader.ReadUInt32(), fontReader.ReadUInt32(), fontReader.ReadUInt32())); - } - Cmap.tables.put(fmtOffset, f); - } - } - } - } - // 读取表 glyf (字体轮廓数据表) - for (Directory Temp : directorys) { - if (Temp.tag.equals("glyf")) { - int glyfCount = maxp.numGlyphs; - for (int i = 0; i < glyfCount; ) { - fontReader.index = Temp.offset + loca.get(i); - ++i; - int glyfNextIndex = i < glyfCount ? loca.get(i) : Temp.length; - - byte[] glyph; - short numberOfContours = fontReader.ReadInt16(); - if (numberOfContours > 0) { - short g_xMin = fontReader.ReadInt16(); - short g_yMin = fontReader.ReadInt16(); - short g_xMax = fontReader.ReadInt16(); - short g_yMax = fontReader.ReadInt16(); - int[] endPtsOfContours = fontReader.GetUInt16Array(numberOfContours); - glyph = fontReader.GetBytes(glyfNextIndex - (fontReader.index - Temp.offset)); - } else { - glyph = fontReader.GetBytes(glyfNextIndex - (fontReader.index - 2)); - } - glyf.add(getHexFromBytes(glyph)); - } - } + directorys.put(d.tag, d); } - // 建立Unicode&Glyph双向表 + Log.i("[queryTTF]", "解析表 name"); // 字体信息,包含版权、名称、作者等... + readNameTable(buffer); + Log.i("[queryTTF]", "解析表 head"); // 获取 head.indexToLocFormat + readHeadTable(buffer); + Log.i("[queryTTF]", "解析表 cmap"); // Unicode编码->轮廓索引 对照表 + readCmapTable(buffer); + Log.i("[queryTTF]", "解析表 loca"); // 轮廓数据偏移地址表 + readLocaTable(buffer); + Log.i("[queryTTF]", "解析表 maxp"); // 获取 maxp.numGlyphs 字体轮廓数量 + readMaxpTable(buffer); + Log.i("[queryTTF]", "解析表 glyf"); // 字体轮廓数据表,需要解析loca,maxp表后计算 + readGlyfTable(buffer); + + Log.i("[queryTTF]", "创建Unicode&Glyph映射表"); for (int key = 0; key < 130000; ++key) { -// if (key == 0xFF) key = 0x3400; - int gid = queryGlyfIndex(key); + Integer gid = queryGlyfIndex(key); if (gid >= glyf.size()) continue; unicodeToGlyphIndex.put(key, gid); var val = glyf.get(gid); @@ -442,27 +498,24 @@ public class QueryTTF { if (glyphToUnicode.containsKey(val)) continue; glyphToUnicode.put(val, key); } + Log.i("[queryTTF]", "字体处理完成"); } - /** - * 获取字体信息 (1=字体名称) - * - * @param nameId 传入十进制字体信息索引 - * @return 返回查询结果字符串 - */ - public String getNameById(int nameId) { - for (Directory Temp : directorys) { - if (!Temp.tag.equals("name")) continue; - fontReader.index = Temp.offset; - break; - } - for (NameRecord record : name.records) { - if (record.nameID != nameId) continue; - fontReader.index += name.stringOffset + record.offset; - return fontReader.ReadStrings(record.length, record.platformID == 1 ? StandardCharsets.UTF_8 : StandardCharsets.UTF_16BE); - } - return "error"; - } +// /** +// * 获取字体信息 (1=字体名称) +// * +// * @param nameId 传入十进制字体信息索引 +// * @return 返回查询结果字符串 +// */ +// public String getNameById(int nameId) { +// fontReader.index = Objects.requireNonNull(directorys.get("name")).offset; +// for (NameRecord record : name.records) { +// if (record.nameID != nameId) continue; +// fontReader.index += name.stringOffset + record.offset; +// return fontReader.ReadStrings(record.length, record.platformID == 1 ? StandardCharsets.UTF_8 : StandardCharsets.UTF_16BE); +// } +// return "error"; +// } /** * 使用Unicode值查找轮廓索引 @@ -472,10 +525,11 @@ public class QueryTTF { */ public int queryGlyfIndex(int unicode) { if (unicode == 0) return 0; + int fmtKey = 0; - for (Pair item : pps) { + for (var item : pps) { for (CmapRecord record : Cmap.records) { - if ((item.getLeft() == record.platformID) && (item.getRight() == record.encodingID)) { + if ((item[0] == record.platformID) && (item[1] == record.encodingID)) { fmtKey = record.offset; break; } @@ -512,10 +566,10 @@ public class QueryTTF { if (0 <= index && index < tab.glyphIdArray.length) glyfID = tab.glyphIdArray[index]; } else if (fmt == 12) { CmapFormat12 tab = (CmapFormat12) table; - if (unicode > tab.groups.get(tab.numGroups - 1).getMiddle()) return 0; + if (unicode > tab.groups.get(tab.numGroups - 1)[1]) return 0; for (int i = 0; i < tab.numGroups; i++) { - if (tab.groups.get(i).getLeft() <= unicode && unicode <= tab.groups.get(i).getMiddle()) { - glyfID = tab.groups.get(i).getRight() + unicode - tab.groups.get(i).getLeft(); + if (tab.groups.get(i)[0] <= unicode && unicode <= tab.groups.get(i)[1]) { + glyfID = tab.groups.get(i)[2] + unicode - tab.groups.get(i)[0]; break; } } @@ -564,14 +618,8 @@ public class QueryTTF { */ public String getHexFromBytes(byte[] glyph) { if (glyph == null) return ""; - StringBuilder sb = new StringBuilder(); - for (byte b : glyph) { - String hex = Integer.toHexString(b); - if (hex.length() == 1) { - sb.append("0");//当16进制为个位数时,在前面补0 - } - sb.append(hex);//将16进制加入字符串 - } - return sb.toString().toUpperCase(); + StringBuilder hexString = new StringBuilder(); + for (byte b : glyph) hexString.append(String.format("%02X", b)); + return hexString.toString(); } }