📄 truetypefont.java
字号:
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(); 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() throws DocumentException, IOException { 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(); } } 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 */ 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -