📄 truetypefont.java
字号:
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();
os_2.sTypoLineGap = rf.readShort();
os_2.usWinAscent = rf.readUnsignedShort();
os_2.usWinDescent = rf.readUnsignedShort();
if (version > 1) {
rf.skipBytes(10);
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();
String postscriptName;
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(' ', '-');
}
/** Reads the font data.
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
*/
void process() throws DocumentException, IOException {
tables = new HashMap();
try {
rf = new RandomAccessFile(fileName, "r");
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);
if (rf.readInt() != 0x00010000)
throw new DocumentException(fileName + " is not a valid TTF 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);
}
fontName = getBaseFont();
fillTables();
readGlyphWidths();
readCMaps();
readKerning();
}
finally {
if (rf != null)
rf.close();
}
}
/** 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
*/
private String readStandardString(int length) throws IOException {
byte buf[] = new byte[length];
rf.readFully(buf);
try {
return new String(buf, PdfObject.ENCODING);
}
catch (Exception e) {
return new String(buf);
}
}
/** 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
*/
private 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
*/
public int getGlyphWidth(int glyph) {
if (glyph >= GlyphWidths.length)
glyph = GlyphWidths.length - 1;
return GlyphWidths[glyph];
}
/** Reads the several maps from the table 'cmap'. The maps of interest are 1.0 for symbolic
* fonts and 3.1 for all others. A symbolic font is defined as having the map 3.0.
* @throws DocumentException the font is invalid
* @throws IOException the font file could not be read
*/
void readCMaps() throws DocumentException, IOException {
int table_location[];
table_location = (int[])tables.get("cmap");
if (table_location == null)
throw new DocumentException("Table 'cmap' does not exist in " + fileName + style);
rf.seek(table_location[0]);
rf.skipBytes(2);
int num_tables = rf.readUnsignedShort();
fontSpecific = false;
int map10 = 0;
int map31 = 0;
for (int k = 0; k < num_tables; ++k) {
int platId = rf.readUnsignedShort();
int platSpecId = rf.readUnsignedShort();
int offset = rf.readInt();
if (platId == 3 && platSpecId == 0) {
fontSpecific = true;
}
else if (platId == 3 && platSpecId == 1) {
map31 = offset;
}
if (platId == 1 && platSpecId == 0) {
map10 = offset;
}
}
if (map10 > 0) {
rf.seek(table_location[0] + map10);
int format = rf.readUnsignedShort();
switch (format) {
case 0:
cmap10 = readFormat0();
break;
case 4:
cmap10 = readFormat4();
break;
case 6:
cmap10 = readFormat6();
break;
}
}
if (map31 > 0) {
rf.seek(table_location[0] + map31);
int format = rf.readUnsignedShort();
if (format == 4) {
cmap31 = readFormat4();
}
}
}
/** The information in the maps of the table 'cmap' is coded in several formats.
* Format 0 is the Apple standard character to glyph index mapping table.
* @return a <CODE>HashMap</CODE> representing this map
* @throws IOException the font file could not be read
*/
HashMap readFormat0() throws IOException {
HashMap h = new HashMap();
rf.skipBytes(4);
for (int k = 0; k < 256; ++k) {
int r[] = new int[2];
r[0] = rf.readUnsignedByte();
r[1] = getGlyphWidth(r[0]);
h.put(new Integer(k), r);
}
return h;
}
/** The information in the maps of the table 'cmap' is coded in several formats.
* Format 4 is the Microsoft standard character to glyph index mapping table.
* @return a <CODE>HashMap</CODE> representing this map
* @throws IOException the font file could not be read
*/
HashMap readFormat4() throws IOException {
HashMap h = new HashMap();
int table_lenght = rf.readUnsignedShort();
rf.skipBytes(2);
int segCount = rf.readUnsignedShort() / 2;
rf.skipBytes(6);
int endCount[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
endCount[k] = rf.readUnsignedShort();
}
rf.skipBytes(2);
int startCount[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
startCount[k] = rf.readUnsignedShort();
}
int idDelta[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
idDelta[k] = rf.readUnsignedShort();
}
int idRO[] = new int[segCount];
for (int k = 0; k < segCount; ++k) {
idRO[k] = rf.readUnsignedShort();
}
int glyphId[] = new int[table_lenght / 2 - 8 - segCount * 4];
for (int k = 0; k < glyphId.length; ++k) {
glyphId[k] = rf.readUnsignedShort();
}
for (int k = 0; k < segCount; ++k) {
int glyph;
for (int j = startCount[k]; j <= endCount[k] && j != 0xFFFF; ++j) {
if (idRO[k] == 0) {
glyph = (j + idDelta[k]) & 0xFFFF;
}
else {
int idx = k + idRO[k] / 2 - segCount + j - startCount[k];
glyph = (glyphId[idx] + idDelta[k]) & 0xFFFF;
}
int r[] = new int[2];
r[0] = glyph;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -