Java全面解析ttf字體的信息
Java解析ttf字體的信息
TTF(TrueType Font)文件格式復(fù)雜,包含了多個(gè)表格,每個(gè)表格存儲(chǔ)了不同的字體信息。
前提是ttf要包含這些表格信息。
通過(guò)代碼解析 TTF 文件,你可以獲取以下內(nèi)容:
public static final int COPYRIGHT = 0; // 版權(quán)信息 public static final int FAMILY_NAME = 1; // 字體家族名稱 public static final int FONT_SUBFAMILY_NAME = 2; // 字體子家族名稱(例如:粗體、斜體等) public static final int UNIQUE_FONT_IDENTIFIER = 3; // 唯一字體標(biāo)識(shí)符 public static final int FULL_FONT_NAME = 4; // 完整字體名稱 public static final int VERSION = 5; // 字體版本信息 public static final int POSTSCRIPT_NAME = 6; // PostScript名稱 public static final int TRADEMARK = 7; // 商標(biāo)信息 public static final int MANUFACTURER = 8; // 制造商信息 public static final int DESIGNER = 9; // 設(shè)計(jì)師信息 public static final int DESCRIPTION = 10; // 字體描述 public static final int URL_VENDOR = 11; // 制造商的URL public static final int URL_DESIGNER = 12; // 設(shè)計(jì)師的URL public static final int LICENSE_DESCRIPTION = 13; // 授權(quán)描述 public static final int LICENSE_INFO_URL = 14; // 授權(quán)信息的URL
以下是數(shù)據(jù)示例:
{0=Digitized data copyright ? 2007, Google Corporation., 1=Droid Sans Mono, 2=Regular, 3=Ascender - Droid Sans Mono, 4=Droid Sans Mono, 5=Version 1.00 build 113, 6=DroidSansMono, 7=Droid is a trademark of Google and may be registered in certain jurisdictions., 8=Ascender Corporation, 10=Droid Sans is a humanist sans serif typeface designed for user interfaces and electronic communication., 11=http://www.ascendercorp.com/, 12=http://www.ascendercorp.com/typedesigners.html, 13=Licensed under the Apache License, Version 2.0, 14=http://www.apache.org/licenses/LICENSE-2.0, 18=?潩搠卡湳?潮?} {0=Copyright 上海字魂網(wǎng)絡(luò)科技有限公司, 1=字魂再見(jiàn)怪獸體(商用需授權(quán)), 2=Regular, 3=ZHZJGST_T, 4=字魂再見(jiàn)怪獸體(商用需授權(quán)), 5=Version 2.00, 6=ZHZJGST_T, 7=字魂 ?, 8=上海字魂網(wǎng)絡(luò)科技有限公司, 9=字魂網(wǎng), 10=字魂聯(lián)名系列, 11=https://izihun.com/, 12=https://izihun.com/, 13=商用需購(gòu)買授權(quán),請(qǐng)?jiān)L問(wèn): https://izihun.com/, 16=字魂再見(jiàn)怪獸體(商用需授權(quán)), 17=常規(guī)體} {0=Digitized data copyright ? 2007, Google Corporation., 1=Droid Sans Mono, 2=Regular, 3=Ascender - Droid Sans Mono, 4=Droid Sans Mono, 5=Version 1.00 build 113, 6=DroidSansMono, 7=Droid is a trademark of Google and may be registered in certain jurisdictions., 8=Ascender Corporation, 10=Droid Sans is a humanist sans serif typeface designed for user interfaces and electronic communication., 11=http://www.ascendercorp.com/, 12=http://www.ascendercorp.com/typedesigners.html, 13=Licensed under the Apache License, Version 2.0, 14=http://www.apache.org/licenses/LICENSE-2.0, 18=?潩搠卡湳?潮?}
1.基本信息:
- 字體名稱:包括全名、家族名、子家族名等。
- 版本信息:字體的版本號(hào)。
- 版權(quán)和許可證:版權(quán)聲明、許可描述等信息。
2.字符映射:
- 字形表(glyf):包含了每個(gè)字符的實(shí)際輪廓(即矢量數(shù)據(jù))。
- 字形數(shù)據(jù):定義了每個(gè)字符的圖形表示方式。
3.表格信息:
- 表目錄(table directory):包含所有表格的名稱、偏移量和長(zhǎng)度。
- 字體頭(head):字體的基本信息,如字體的最小和最大字形的邊界框。
4.度量信息:
- 水平度量表(hmtx):包含每個(gè)字形的水平度量數(shù)據(jù)。
- 垂直度量表(vmtx):包含每個(gè)字形的垂直度量數(shù)據(jù)。
5.表格詳情:
- 名稱表(name):存儲(chǔ)字體的各種名稱信息,如字體的全名、家族名、子家族名等。
- 字符映射表(cmap):定義了字符代碼與字形索引之間的映射關(guān)系。
- 頭表(head):提供了字體的一些基本信息,如字體的版本、創(chuàng)建時(shí)間等。
- 控制點(diǎn)表(loca):提供字形輪廓數(shù)據(jù)的偏移量。
6.額外的表格:
- 垂直和水平指標(biāo)表(hhea 和 vhea):包含了字體的水平和垂直基線指標(biāo)。
- 輪廓圖像表(glyf):存儲(chǔ)了每個(gè)字形的實(shí)際輪廓。
代碼解析示例
1.建立工具類
package com.example.psd.font; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; /** * TTF 字體文件解析器 */ public class TTFParser { public static final int COPYRIGHT = 0; public static final int FAMILY_NAME = 1; public static final int FONT_SUBFAMILY_NAME = 2; public static final int UNIQUE_FONT_IDENTIFIER = 3; public static final int FULL_FONT_NAME = 4; public static final int VERSION = 5; public static final int POSTSCRIPT_NAME = 6; public static final int TRADEMARK = 7; public static final int MANUFACTURER = 8; public static final int DESIGNER = 9; public static final int DESCRIPTION = 10; public static final int URL_VENDOR = 11; public static final int URL_DESIGNER = 12; public static final int LICENSE_DESCRIPTION = 13; public static final int LICENSE_INFO_URL = 14; private final Map<Integer, String> fontProperties = new HashMap<>(); /** * 獲取全字體名稱,如果不可用則獲取字體家族名稱。 * * @return 字體名稱 */ public String getFontName() { return fontProperties.getOrDefault(FULL_FONT_NAME, fontProperties.get(FAMILY_NAME)); } /** * 獲取特定的字體屬性。 * * @param nameID 屬性 ID * @return 屬性值 */ public String getFontProperty(int nameID) { return fontProperties.get(nameID); } /** * 獲取所有字體屬性。 * * @return 字體屬性映射 */ public Map<Integer, String> getFontProperties() { return fontProperties; } /** * 解析 TTF 文件并提取字體屬性。 * * @param fileName TTF 文件路徑 * @throws IOException 如果發(fā)生 I/O 錯(cuò)誤 */ public void parse(String fileName) throws IOException { fontProperties.clear(); try (RandomAccessFile raf = new RandomAccessFile(fileName, "r")) { parseInner(raf); } } private void parseInner(RandomAccessFile raf) throws IOException { int majorVersion = raf.readUnsignedShort(); int minorVersion = raf.readUnsignedShort(); int numOfTables = raf.readUnsignedShort(); if (majorVersion != 1 || minorVersion != 0) { return; // 不支持的版本 } // 跳到表目錄 raf.seek(12); // 跳過(guò)版本信息和表數(shù) boolean found = false; TableDirectory tableDirectory = new TableDirectory(); for (int i = 0; i < numOfTables; i++) { byte[] nameBytes = new byte[4]; raf.readFully(nameBytes); tableDirectory.name = new String(nameBytes, StandardCharsets.ISO_8859_1); tableDirectory.checkSum = raf.readInt(); tableDirectory.offset = raf.readInt(); tableDirectory.length = raf.readInt(); if ("name".equalsIgnoreCase(tableDirectory.name)) { found = true; break; } } if (!found) { return; // 未找到 'name' 表 } raf.seek(tableDirectory.offset); NameTableHeader nameTableHeader = new NameTableHeader(); nameTableHeader.fSelector = raf.readUnsignedShort(); nameTableHeader.nRCount = raf.readUnsignedShort(); nameTableHeader.storageOffset = raf.readUnsignedShort(); for (int i = 0; i < nameTableHeader.nRCount; i++) { NameRecord nameRecord = new NameRecord(); nameRecord.platformID = raf.readUnsignedShort(); nameRecord.encodingID = raf.readUnsignedShort(); nameRecord.languageID = raf.readUnsignedShort(); nameRecord.nameID = raf.readUnsignedShort(); nameRecord.stringLength = raf.readUnsignedShort(); nameRecord.stringOffset = raf.readUnsignedShort(); long pos = raf.getFilePointer(); raf.seek(tableDirectory.offset + nameRecord.stringOffset + nameTableHeader.storageOffset); byte[] bf = new byte[nameRecord.stringLength]; raf.readFully(bf); String value = new String(bf, StandardCharsets.UTF_16); fontProperties.put(nameRecord.nameID, value); // 打印出可能的授權(quán)信息 if (nameRecord.nameID == TTFParser.COPYRIGHT || nameRecord.nameID == TTFParser.LICENSE_DESCRIPTION) { System.out.println("Found information: " + value); System.out.println(); } raf.seek(pos); } } /** * 檢查字體文件中是否包含版權(quán)聲明。 * * @return 如果找到版權(quán)聲明,返回 true;否則返回 false */ public boolean hasCopyrightInfo() { return fontProperties.containsKey(COPYRIGHT); } /** * 檢查字體文件中是否包含商用授權(quán)信息。 * * @return 返回一個(gè)包含兩個(gè)布爾值的數(shù)組,第一個(gè)表示是否允許商用,第二個(gè)表示是否需要授權(quán)。 */ public boolean[] checkCommercialUseAndAuthorization() { boolean isCommercialUseAllowed = false; boolean isAuthorizationRequired = false; String licenseDescription = fontProperties.get(LICENSE_DESCRIPTION); if (licenseDescription != null) { // 解析 licenseDescription 中的關(guān)鍵詞來(lái)判斷 String descriptionLower = licenseDescription.toLowerCase(); if (descriptionLower.contains("commercial use allowed")) { isCommercialUseAllowed = true; } if (descriptionLower.contains("authorization required")) { isAuthorizationRequired = true; } } String licenseInfoURL = fontProperties.get(LICENSE_INFO_URL); System.out.println("============111111" + fontProperties); if (licenseInfoURL != null) { // 可以通過(guò)訪問(wèn)此URL來(lái)確認(rèn)授權(quán)信息 System.out.println("檢查授權(quán)信息,請(qǐng)?jiān)L問(wèn): " + licenseInfoURL); // 假設(shè)如果有 URL 說(shuō)明需要進(jìn)一步確認(rèn)授權(quán) isAuthorizationRequired = true; } return new boolean[]{isCommercialUseAllowed, isAuthorizationRequired}; } @Override public String toString() { return fontProperties.toString(); } private static class TableDirectory { String name; int checkSum; int offset; int length; } private static class NameTableHeader { int fSelector; int nRCount; int storageOffset; } private static class NameRecord { int platformID; int encodingID; int languageID; int nameID; int stringLength; int stringOffset; } }
2.demo
package com.example.psd.font; import com.example.psd.font.TTFParser; import java.io.File; import java.io.FilenameFilter; public class TTFParserExample { public static void main(String[] args) { // 指定 TTF 文件所在目錄 File fontDir = new File("D:\\測(cè)試"); // 列出目錄中的所有 TTF 文件 File[] files = fontDir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".ttf"); } }); // 處理每個(gè) TTF 文件 if (files != null) { for (File file : files) { TTFParser parser = new TTFParser(); try { parser.parse(file.getAbsolutePath()); // 獲取并打印字體名稱 String fontName = parser.getFontName(); System.out.println("Font name: " + fontName); // 如果需要獲取其他屬性,可以使用類似的方式 String familyName = parser.getFontProperty(TTFParser.FAMILY_NAME); System.out.println("Family name: " + familyName); } catch (Exception e) { System.err.println("Error parsing font file: " + file.getAbsolutePath()); e.printStackTrace(); } } } else { System.out.println("No TTF files found in the specified directory."); } } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于Java內(nèi)存訪問(wèn)重排序的研究
文章主要介紹了重排序現(xiàn)象及其在多線程編程中的影響,包括內(nèi)存可見(jiàn)性問(wèn)題和Java內(nèi)存模型中對(duì)重排序的規(guī)則2025-01-01java如何讀取某個(gè)文件夾中的全部文件(包括子文件夾)
這篇文章主要介紹了java如何讀取某個(gè)文件夾中的全部文件(包括子文件夾),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12SpringCloud修改Feign日志記錄級(jí)別過(guò)程淺析
OpenFeign源于Netflix的Feign,是http通信的客戶端。屏蔽了網(wǎng)絡(luò)通信的細(xì)節(jié),直接面向接口的方式開(kāi)發(fā),讓開(kāi)發(fā)者感知不到網(wǎng)絡(luò)通信細(xì)節(jié)。所有遠(yuǎn)程調(diào)用,都像調(diào)用本地方法一樣完成2023-02-02idea與eclipse項(xiàng)目相互導(dǎo)入的過(guò)程(圖文教程)
這篇文章主要介紹了idea與eclipse項(xiàng)目相互導(dǎo)入的過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Java Elastic Job動(dòng)態(tài)添加任務(wù)實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Java Elastic Job動(dòng)態(tài)添加任務(wù)實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Maven多模塊之父子關(guān)系的創(chuàng)建
這篇文章主要介紹了Maven多模塊之父子關(guān)系的創(chuàng)建,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03SpringBoot整合Web之CORS支持與配置類和 XML配置及注冊(cè)攔截器
這篇文章主要介紹了SpringBoot整合Web開(kāi)發(fā)中CORS支持與配置類和 XML配置及注冊(cè)攔截器的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08異常try?catch的常見(jiàn)四類方式(案例代碼)
這篇文章主要介紹了異常try?catch的常見(jiàn)四類方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05