Java全面解析ttf字體的信息
更新時間:2025年01月14日 15:05:00 作者:念九_ysl
文章介紹了Java如何解析TTF字體文件,提取字體的基本信息、版本信息、版權和許可證、字符映射以及各種表格信息,通過代碼解析,可以獲取字體的詳細描述和度量數(shù)據(jù)
Java解析ttf字體的信息
TTF(TrueType Font)文件格式復雜,包含了多個表格,每個表格存儲了不同的字體信息。
前提是ttf要包含這些表格信息。
通過代碼解析 TTF 文件,你可以獲取以下內容:
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; // PostScript名稱 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; // 制造商的URL public static final int URL_DESIGNER = 12; // 設計師的URL public static final int LICENSE_DESCRIPTION = 13; // 授權描述 public static final int LICENSE_INFO_URL = 14; // 授權信息的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)絡科技有限公司, 1=字魂再見怪獸體(商用需授權), 2=Regular, 3=ZHZJGST_T,
4=字魂再見怪獸體(商用需授權), 5=Version 2.00, 6=ZHZJGST_T, 7=字魂 ?,
8=上海字魂網(wǎng)絡科技有限公司, 9=字魂網(wǎng), 10=字魂聯(lián)名系列, 11=https://izihun.com/,
12=https://izihun.com/, 13=商用需購買授權,請訪問: https://izihun.com/,
16=字魂再見怪獸體(商用需授權), 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.基本信息:
- 字體名稱:包括全名、家族名、子家族名等。
- 版本信息:字體的版本號。
- 版權和許可證:版權聲明、許可描述等信息。
2.字符映射:
- 字形表(glyf):包含了每個字符的實際輪廓(即矢量數(shù)據(jù))。
- 字形數(shù)據(jù):定義了每個字符的圖形表示方式。
3.表格信息:
- 表目錄(table directory):包含所有表格的名稱、偏移量和長度。
- 字體頭(head):字體的基本信息,如字體的最小和最大字形的邊界框。
4.度量信息:
- 水平度量表(hmtx):包含每個字形的水平度量數(shù)據(jù)。
- 垂直度量表(vmtx):包含每個字形的垂直度量數(shù)據(jù)。
5.表格詳情:
- 名稱表(name):存儲字體的各種名稱信息,如字體的全名、家族名、子家族名等。
- 字符映射表(cmap):定義了字符代碼與字形索引之間的映射關系。
- 頭表(head):提供了字體的一些基本信息,如字體的版本、創(chuàng)建時間等。
- 控制點表(loca):提供字形輪廓數(shù)據(jù)的偏移量。
6.額外的表格:
- 垂直和水平指標表(hhea 和 vhea):包含了字體的水平和垂直基線指標。
- 輪廓圖像表(glyf):存儲了每個字形的實際輪廓。
代碼解析示例
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 錯誤
*/
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); // 跳過版本信息和表數(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);
// 打印出可能的授權信息
if (nameRecord.nameID == TTFParser.COPYRIGHT || nameRecord.nameID == TTFParser.LICENSE_DESCRIPTION) {
System.out.println("Found information: " + value);
System.out.println();
}
raf.seek(pos);
}
}
/**
* 檢查字體文件中是否包含版權聲明。
*
* @return 如果找到版權聲明,返回 true;否則返回 false
*/
public boolean hasCopyrightInfo() {
return fontProperties.containsKey(COPYRIGHT);
}
/**
* 檢查字體文件中是否包含商用授權信息。
*
* @return 返回一個包含兩個布爾值的數(shù)組,第一個表示是否允許商用,第二個表示是否需要授權。
*/
public boolean[] checkCommercialUseAndAuthorization() {
boolean isCommercialUseAllowed = false;
boolean isAuthorizationRequired = false;
String licenseDescription = fontProperties.get(LICENSE_DESCRIPTION);
if (licenseDescription != null) {
// 解析 licenseDescription 中的關鍵詞來判斷
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) {
// 可以通過訪問此URL來確認授權信息
System.out.println("檢查授權信息,請訪問: " + licenseInfoURL);
// 假設如果有 URL 說明需要進一步確認授權
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:\\測試");
// 列出目錄中的所有 TTF 文件
File[] files = fontDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".ttf");
}
});
// 處理每個 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.");
}
}
}總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java Elastic Job動態(tài)添加任務實現(xiàn)過程解析
這篇文章主要介紹了Java Elastic Job動態(tài)添加任務實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-08-08
SpringBoot整合Web之CORS支持與配置類和 XML配置及注冊攔截器
這篇文章主要介紹了SpringBoot整合Web開發(fā)中CORS支持與配置類和 XML配置及注冊攔截器的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08

