📄 truetypefont.java
字号:
for (int k = 0; k < entries; ++k) locaTable[k] = rf.readInt(); } tableLocation = (int[])tables.get("glyf"); if (tableLocation == null) throw new DocumentException("Table 'glyf' does not exist in " + fileName + style); int tableGlyphOffset = tableLocation[0]; bboxes = new int[locaTable.length - 1][]; for (int glyph = 0; glyph < locaTable.length - 1; ++glyph) { int start = locaTable[glyph]; if (start != locaTable[glyph + 1]) { rf.seek(tableGlyphOffset + start + 2); bboxes[glyph] = new int[]{ (rf.readShort() * 1000) / head.unitsPerEm, (rf.readShort() * 1000) / head.unitsPerEm, (rf.readShort() * 1000) / head.unitsPerEm, (rf.readShort() * 1000) / head.unitsPerEm}; } } } /** 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; int map30 = 0; int mapExt = 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; map30 = offset; } else if (platId == 3 && platSpecId == 1) { map31 = offset; } else if (platId == 3 && platSpecId == 10) { mapExt = 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(); } } if (map30 > 0) { rf.seek(table_location[0] + map30); int format = rf.readUnsignedShort(); if (format == 4) { cmap10 = readFormat4(); } } if (mapExt > 0) { rf.seek(table_location[0] + mapExt); int format = rf.readUnsignedShort(); switch (format) { case 0: cmapExt = readFormat0(); break; case 4: cmapExt = readFormat4(); break; case 6: cmapExt = readFormat6(); break; case 12: cmapExt = readFormat12(); break; } } } HashMap readFormat12() throws IOException { HashMap h = new HashMap(); rf.skipBytes(2); int table_lenght = rf.readInt(); rf.skipBytes(4); int nGroups = rf.readInt(); for (int k = 0; k < nGroups; k++) { int startCharCode = rf.readInt(); int endCharCode = rf.readInt(); int startGlyphID = rf.readInt(); for (int i = startCharCode; i <= endCharCode; i++) { int[] r = new int[2]; r[0] = startGlyphID; r[1] = getGlyphWidth(r[0]); h.put(new Integer(i), r); startGlyphID++; } } return h; } /** 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]; if (idx >= glyphId.length) continue; glyph = (glyphId[idx] + idDelta[k]) & 0xFFFF; } int r[] = new int[2]; r[0] = glyph; r[1] = getGlyphWidth(r[0]); h.put(new Integer(fontSpecific ? ((j & 0xff00) == 0xf000 ? j & 0xff : j) : j), r); } } return h; } /** The information in the maps of the table 'cmap' is coded in several formats. * Format 6 is a trimmed table mapping. It is similar to format 0 but can have * less than 256 entries. * @return a <CODE>HashMap</CODE> representing this map * @throws IOException the font file could not be read */ HashMap readFormat6() throws IOException { HashMap h = new HashMap(); rf.skipBytes(4); int start_code = rf.readUnsignedShort(); int code_count = rf.readUnsignedShort(); for (int k = 0; k < code_count; ++k) { int r[] = new int[2]; r[0] = rf.readUnsignedShort(); r[1] = getGlyphWidth(r[0]); h.put(new Integer(k + start_code), r); } return h; } /** Reads the kerning information from the 'kern' table. * @throws IOException the font file could not be read */ void readKerning() throws IOException { int table_location[]; table_location = (int[])tables.get("kern"); if (table_location == null) return; rf.seek(table_location[0] + 2); int nTables = rf.readUnsignedShort(); int checkpoint = table_location[0] + 4; int length = 0; for (int k = 0; k < nTables; ++k) { checkpoint += length; rf.seek(checkpoint); rf.skipBytes(2); length = rf.readUnsignedShort(); int coverage = rf.readUnsignedShort(); if ((coverage & 0xfff7) == 0x0001) { int nPairs = rf.readUnsignedShort(); rf.skipBytes(6); for (int j = 0; j < nPairs; ++j) { int pair = rf.readInt(); int value = rf.readShort() * 1000 / head.unitsPerEm; kerning.put(pair, value); } } } } /** Gets the kerning between two Unicode chars. * @param char1 the first char * @param char2 the second char * @return the kerning to be applied */ public int getKerning(int char1, int char2) { int metrics[] = getMetricsTT(char1); if (metrics == null) return 0; int c1 = metrics[0]; metrics = getMetricsTT(char2); if (metrics == null) return 0; int c2 = metrics[0]; return kerning.get((c1 << 16) + c2); } /** Gets the width from the font according to the unicode char <CODE>c</CODE>. * If the <CODE>name</CODE> is null it's a symbolic font. * @param c the unicode char * @param name the glyph name * @return the width of the char */ int getRawWidth(int c, String name) { int[] metric = getMetricsTT(c); if (metric == null) return 0; return metric[1]; } /** Generates the font descriptor for this font. * @return the PdfDictionary containing the font descriptor or <CODE>null</CODE> * @param subsetPrefix the subset prefix * @param fontStream the indirect reference to a PdfStream containing the font or <CODE>null</CODE> * @throws DocumentException if there is an error */ protected PdfDictionary getFontDescriptor(PdfIndirectReference fontStream, String subsetPrefix, PdfIndirectReference cidset) { PdfDictionary dic = new PdfDictionary(PdfName.FONTDESCRIPTOR); dic.put(PdfName.ASCENT, new PdfNumber(os_2.sTypoAscender * 1000 / head.unitsPerEm)); dic.put(PdfName.CAPHEIGHT, new PdfNumber(os_2.sCapHeight * 1000 / head.unitsPerEm)); dic.put(PdfName.DESCENT, new PdfNumber(os_2.sTypoDescender * 1000 / head.unitsPerEm)); dic.put(PdfName.FONTBBOX, new PdfRectangle( head.xMin * 1000 / head.unitsPerEm, head.yMin * 1000 / head.unitsPerEm, head.xMax * 1000 / head.unitsPerEm, head.yMax * 1000 / head.unitsPerEm)); if (cidset != null) dic.put(PdfName.CIDSET, cidset); if (cff) { if (encoding.startsWith("Identity-")) dic.put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName+"-"+encoding)); else dic.put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName + style)); } else dic.put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName + style)); dic.put(PdfName.ITALICANGLE, new PdfNumber(italicAngle)); dic.put(PdfName.STEMV, new PdfNumber(80)); if (fontStream != null) { if (cff) dic.put(PdfName.FONTFILE3, fontStream); else dic.put(PdfName.FONTFILE2, fontStream); } int flags = 0; if (isFixedPitch) flags |= 1; flags |= fontSpecific ? 4 : 32; if ((head.macStyle & 2) != 0) flags |= 64; if ((head.macStyle & 1) != 0) flags |= 262144; dic.put(PdfName.FLAGS, new PdfNumber(flags)); return dic; } /** Generates the font dictionary for this font. * @return the PdfDictionary containing the font dictionary * @param subsetPrefix the subset prefx * @param firstChar the first valid character * @param lastChar the last valid character * @param shortTag a 256 bytes long <CODE>byte</CODE> array where each unused byte is represented by 0 * @param fontDescriptor the indirect reference to a PdfDictionary containing the font descriptor or <CODE>null</CODE> * @throws DocumentException if there is an error */ protected PdfDictionary getFontBaseType(PdfIndirectReference fontDescriptor, String subsetPrefix, int firstChar, int lastChar, byte shortTag[]) { PdfDictionary dic = new PdfDictionary(PdfName.FONT); if (cff) { dic.put(PdfName.SUBTYPE, PdfName.TYPE1); dic.put(PdfName.BASEFONT, new PdfName(fontName + style)); } else { dic.put(PdfName.SUBTYPE, PdfName.TRUETYPE); dic.put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName + style)); } dic.put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName + style)); if (!fontSpecific) { for (int k = firstChar; k <= lastChar; ++k) { if (!differences[k].equals(notdef)) { firstChar = k; break; } } if (encoding.equals("Cp1252") || encoding.equals("MacRoman")) dic.put(PdfName.ENCODING, encoding.equals("Cp1252") ? PdfName.WIN_ANSI_ENCODING : PdfName.MAC_ROMAN_ENCODING); else { PdfDictionary enc = new PdfDictionary(PdfName.ENCODING); PdfArray dif = new PdfArray(); boolean gap = true; for (int k = firstChar; k <= lastChar; ++k) { if (shortTag[k] != 0) { if (gap) { dif.add(new PdfNumber(k)); gap = false; } dif.add(new PdfName(differences[k])); } else gap = true; } enc.put(PdfName.DIFFERENCES, dif); dic.put(PdfName.ENCODING, enc); } } dic.put(PdfName.FIRSTCHAR, new PdfNumber(firstChar)); dic.put(PdfName.LASTCHAR, new PdfNumber(lastChar)); PdfArray wd = new PdfArray(); for (int k = firstChar; k <= lastChar; ++k) { if (shortTag[k] == 0) wd.add(new PdfNumber(0)); else wd.add(new PdfNumber(widths[k])); } dic.put(PdfName.WIDTHS, wd); if (fontDescriptor != null) dic.put(PdfName.FONTDESCRIPTOR, fontDescriptor);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -