📄 truetypefont.java
字号:
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
*/
TrueTypeFont(String ttFile, String enc, boolean emb, byte ttfAfm[], boolean justNames) throws DocumentException, IOException {
this.justNames = justNames;
String nameBase = getBaseName(ttFile);
String ttcName = getTTCName(nameBase);
if (nameBase.length() < ttFile.length()) {
style = ttFile.substring(nameBase.length());
}
encoding = enc;
embedded = emb;
fileName = ttcName;
fontType = FONT_TYPE_TT;
ttcIndex = "";
if (ttcName.length() < nameBase.length())
ttcIndex = nameBase.substring(ttcName.length() + 1);
if (fileName.toLowerCase().endsWith(".ttf") || fileName.toLowerCase().endsWith(".otf") || fileName.toLowerCase().endsWith(".ttc")) {
process(ttfAfm);
if (!justNames && embedded && os_2.fsType == 2)
throw new DocumentException(fileName + style + " cannot be embedded due to licensing restrictions.");
}
else
throw new DocumentException(fileName + style + " is not a TTF, OTF or TTC font file.");
if (!encoding.startsWith("#"))
PdfEncodings.convertToBytes(" ", enc); // check if the encoding exists
createEncoding();
}
/** Gets the name from a composed TTC file name.
* If I have for input "myfont.ttc,2" the return will
* be "myfont.ttc".
* @param name the full name
* @return the simple file name
*/
protected static String getTTCName(String name) {
int idx = name.toLowerCase().indexOf(".ttc,");
if (idx < 0)
return name;
else
return name.substring(0, idx + 4);
}
/**
* Reads the tables 'head', 'hhea', 'OS/2' and 'post' filling several variables.
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
*/
void fillTables() throws DocumentException, IOException {
int table_location[];
table_location = (int[])tables.get("head");
if (table_location == null)
throw new DocumentException("Table 'head' does not exist in " + fileName + style);
rf.seek(table_location[0] + 16);
head.flags = rf.readUnsignedShort();
head.unitsPerEm = rf.readUnsignedShort();
rf.skipBytes(16);
head.xMin = rf.readShort();
head.yMin = rf.readShort();
head.xMax = rf.readShort();
head.yMax = rf.readShort();
head.macStyle = rf.readUnsignedShort();
table_location = (int[])tables.get("hhea");
if (table_location == null)
throw new DocumentException("Table 'hhea' does not exist " + fileName + style);
rf.seek(table_location[0] + 4);
hhea.Ascender = rf.readShort();
hhea.Descender = rf.readShort();
hhea.LineGap = rf.readShort();
hhea.advanceWidthMax = rf.readUnsignedShort();
hhea.minLeftSideBearing = rf.readShort();
hhea.minRightSideBearing = rf.readShort();
hhea.xMaxExtent = rf.readShort();
hhea.caretSlopeRise = rf.readShort();
hhea.caretSlopeRun = rf.readShort();
rf.skipBytes(12);
hhea.numberOfHMetrics = rf.readUnsignedShort();
table_location = (int[])tables.get("OS/2");
if (table_location == null)
throw new DocumentException("Table 'OS/2' does not exist in " + fileName + style);
rf.seek(table_location[0]);
int version = rf.readUnsignedShort();
os_2.xAvgCharWidth = rf.readShort();
os_2.usWeightClass = rf.readUnsignedShort();
os_2.usWidthClass = rf.readUnsignedShort();
os_2.fsType = rf.readShort();
os_2.ySubscriptXSize = rf.readShort();
os_2.ySubscriptYSize = rf.readShort();
os_2.ySubscriptXOffset = rf.readShort();
os_2.ySubscriptYOffset = rf.readShort();
os_2.ySuperscriptXSize = rf.readShort();
os_2.ySuperscriptYSize = rf.readShort();
os_2.ySuperscriptXOffset = rf.readShort();
os_2.ySuperscriptYOffset = rf.readShort();
os_2.yStrikeoutSize = rf.readShort();
os_2.yStrikeoutPosition = rf.readShort();
os_2.sFamilyClass = rf.readShort();
rf.readFully(os_2.panose);
rf.skipBytes(16);
rf.readFully(os_2.achVendID);
os_2.fsSelection = rf.readUnsignedShort();
os_2.usFirstCharIndex = rf.readUnsignedShort();
os_2.usLastCharIndex = rf.readUnsignedShort();
os_2.sTypoAscender = rf.readShort();
os_2.sTypoDescender = rf.readShort();
if (os_2.sTypoDescender > 0)
os_2.sTypoDescender = (short)(-os_2.sTypoDescender);
os_2.sTypoLineGap = rf.readShort();
os_2.usWinAscent = rf.readUnsignedShort();
os_2.usWinDescent = rf.readUnsignedShort();
os_2.ulCodePageRange1 = 0;
os_2.ulCodePageRange2 = 0;
if (version > 0) {
os_2.ulCodePageRange1 = rf.readInt();
os_2.ulCodePageRange2 = rf.readInt();
}
if (version > 1) {
rf.skipBytes(2);
os_2.sCapHeight = rf.readShort();
}
else
os_2.sCapHeight = (int)(0.7 * head.unitsPerEm);
table_location = (int[])tables.get("post");
if (table_location == null) {
italicAngle = -Math.atan2(hhea.caretSlopeRun, hhea.caretSlopeRise) * 180 / Math.PI;
return;
}
rf.seek(table_location[0] + 4);
short mantissa = rf.readShort();
int fraction = rf.readUnsignedShort();
italicAngle = (double)mantissa + (double)fraction / 16384.0;
rf.skipBytes(4);
isFixedPitch = rf.readInt() != 0;
}
/**
* Gets the Postscript font name.
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
* @return the Postscript font name
*/
String getBaseFont() throws DocumentException, IOException {
int table_location[];
table_location = (int[])tables.get("name");
if (table_location == null)
throw new DocumentException("Table 'name' does not exist in " + fileName + style);
rf.seek(table_location[0] + 2);
int numRecords = rf.readUnsignedShort();
int startOfStorage = rf.readUnsignedShort();
for (int k = 0; k < numRecords; ++k) {
int platformID = rf.readUnsignedShort();
int platformEncodingID = rf.readUnsignedShort();
int languageID = rf.readUnsignedShort();
int nameID = rf.readUnsignedShort();
int length = rf.readUnsignedShort();
int offset = rf.readUnsignedShort();
if (nameID == 6) {
rf.seek(table_location[0] + startOfStorage + offset);
if (platformID == 0 || platformID == 3)
return readUnicodeString(length);
else
return readStandardString(length);
}
}
File file = new File(fileName);
return file.getName().replace(' ', '-');
}
/** Extracts the names of the font in all the languages available.
* @param id the name id to retrieve
* @throws DocumentException on error
* @throws IOException on error
*/
String[][] getNames(int id) throws DocumentException, IOException {
int table_location[];
table_location = (int[])tables.get("name");
if (table_location == null)
throw new DocumentException("Table 'name' does not exist in " + fileName + style);
rf.seek(table_location[0] + 2);
int numRecords = rf.readUnsignedShort();
int startOfStorage = rf.readUnsignedShort();
ArrayList names = new ArrayList();
for (int k = 0; k < numRecords; ++k) {
int platformID = rf.readUnsignedShort();
int platformEncodingID = rf.readUnsignedShort();
int languageID = rf.readUnsignedShort();
int nameID = rf.readUnsignedShort();
int length = rf.readUnsignedShort();
int offset = rf.readUnsignedShort();
if (nameID == id) {
int pos = rf.getFilePointer();
rf.seek(table_location[0] + startOfStorage + offset);
String name;
if (platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1)){
name = readUnicodeString(length);
}
else {
name = readStandardString(length);
}
names.add(new String[]{String.valueOf(platformID),
String.valueOf(platformEncodingID), String.valueOf(languageID), name});
rf.seek(pos);
}
}
String thisName[][] = new String[names.size()][];
for (int k = 0; k < names.size(); ++k)
thisName[k] = (String[])names.get(k);
return thisName;
}
void checkCff() {
int table_location[];
table_location = (int[])tables.get("CFF ");
if (table_location != null) {
cff = true;
cffOffset = table_location[0];
cffLength = table_location[1];
}
}
/** Reads the font data.
* @param ttfAfm the font as a <CODE>byte</CODE> array, possibly <CODE>null</CODE>
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
*/
void process(byte ttfAfm[]) throws DocumentException, IOException {
tables = new HashMap();
try {
if (ttfAfm == null)
rf = new RandomAccessFileOrArray(fileName);
else
rf = new RandomAccessFileOrArray(ttfAfm);
if (ttcIndex.length() > 0) {
int dirIdx = Integer.parseInt(ttcIndex);
if (dirIdx < 0)
throw new DocumentException("The font index for " + fileName + " must be positive.");
String mainTag = readStandardString(4);
if (!mainTag.equals("ttcf"))
throw new DocumentException(fileName + " is not a valid TTC file.");
rf.skipBytes(4);
int dirCount = rf.readInt();
if (dirIdx >= dirCount)
throw new DocumentException("The font index for " + fileName + " must be between 0 and " + (dirCount - 1) + ". It was " + dirIdx + ".");
rf.skipBytes(dirIdx * 4);
directoryOffset = rf.readInt();
}
rf.seek(directoryOffset);
int ttId = rf.readInt();
if (ttId != 0x00010000 && ttId != 0x4F54544F)
throw new DocumentException(fileName + " is not a valid TTF or OTF file.");
int num_tables = rf.readUnsignedShort();
rf.skipBytes(6);
for (int k = 0; k < num_tables; ++k) {
String tag = readStandardString(4);
rf.skipBytes(4);
int table_location[] = new int[2];
table_location[0] = rf.readInt();
table_location[1] = rf.readInt();
tables.put(tag, table_location);
}
checkCff();
fontName = getBaseFont();
fullName = getNames(4); //full name
familyName = getNames(1); //family name
if (!justNames) {
fillTables();
readGlyphWidths();
readCMaps();
readKerning();
readBbox();
GlyphWidths = null;
}
}
finally {
if (rf != null) {
rf.close();
if (!embedded)
rf = null;
}
}
}
/** Reads a <CODE>String</CODE> from the font file as bytes using the Cp1252
* encoding.
* @param length the length of bytes to read
* @return the <CODE>String</CODE> read
* @throws IOException the font file could not be read
*/
protected String readStandardString(int length) throws IOException {
byte buf[] = new byte[length];
rf.readFully(buf);
try {
return new String(buf, WINANSI);
}
catch (Exception e) {
throw new ExceptionConverter(e);
}
}
/** Reads a Unicode <CODE>String</CODE> from the font file. Each character is
* represented by two bytes.
* @param length the length of bytes to read. The <CODE>String</CODE> will have <CODE>length</CODE>/2
* characters
* @return the <CODE>String</CODE> read
* @throws IOException the font file could not be read
*/
protected String readUnicodeString(int length) throws IOException {
StringBuffer buf = new StringBuffer();
length /= 2;
for (int k = 0; k < length; ++k) {
buf.append(rf.readChar());
}
return buf.toString();
}
/** Reads the glyphs widths. The widths are extracted from the table 'hmtx'.
* The glyphs are normalized to 1000 units.
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
*/
protected void readGlyphWidths() throws DocumentException, IOException {
int table_location[];
table_location = (int[])tables.get("hmtx");
if (table_location == null)
throw new DocumentException("Table 'hmtx' does not exist in " + fileName + style);
rf.seek(table_location[0]);
GlyphWidths = new int[hhea.numberOfHMetrics];
for (int k = 0; k < hhea.numberOfHMetrics; ++k) {
GlyphWidths[k] = (rf.readUnsignedShort() * 1000) / head.unitsPerEm;
rf.readUnsignedShort();
}
}
/** Gets a glyph width.
* @param glyph the glyph to get the width of
* @return the width of the glyph in normalized 1000 units
*/
protected int getGlyphWidth(int glyph) {
if (glyph >= GlyphWidths.length)
glyph = GlyphWidths.length - 1;
return GlyphWidths[glyph];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -