📄 truetypefont.java
字号:
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; r[1] = getGlyphWidth(r[0]); h.put(new Integer(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(); kerning = new HashMap(); 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) { Integer pair = new Integer(rf.readInt()); Integer value = new Integer(((int)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(char char1, char 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]; Integer v = (Integer)kerning.get(new Integer((c1 << 16) + c2)); if (v == null) return 0; else return v.intValue(); } /** 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 */ protected int getRawWidth(int c, String name) { HashMap map = null; if (name == null) map = cmap10; else map = cmap31; if (map == null) return 0; int metric[] = (int[])map.get(new Integer(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) throws DocumentException { PdfDictionary dic = new PdfDictionary(new PdfName("FontDescriptor")); dic.put(new PdfName("Ascent"), new PdfNumber((int)os_2.sTypoAscender * 1000 / head.unitsPerEm)); dic.put(new PdfName("CapHeight"), new PdfNumber((int)os_2.sCapHeight * 1000 / head.unitsPerEm)); dic.put(new PdfName("Descent"), new PdfNumber((int)os_2.sTypoDescender * 1000 / head.unitsPerEm)); dic.put(new PdfName("FontBBox"), new PdfRectangle( (int)head.xMin * 1000 / head.unitsPerEm, (int)head.yMin * 1000 / head.unitsPerEm, (int)head.xMax * 1000 / head.unitsPerEm, (int)head.yMax * 1000 / head.unitsPerEm)); dic.put(new PdfName("FontName"), new PdfName(subsetPrefix + fontName + style)); dic.put(new PdfName("ItalicAngle"), new PdfNumber(italicAngle)); dic.put(new PdfName("StemV"), new PdfNumber(80)); if (fontStream != null) { if (cff) dic.put(new PdfName("FontFile3"), fontStream); else dic.put(new 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(new 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[]) throws DocumentException { PdfDictionary dic = new PdfDictionary(PdfName.FONT); if (cff) dic.put(PdfName.SUBTYPE, new PdfName("Type1")); else dic.put(PdfName.SUBTYPE, new PdfName("TrueType")); 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(new 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(new PdfName("Differences"), dif); dic.put(PdfName.ENCODING, enc); } } dic.put(new PdfName("FirstChar"), new PdfNumber(firstChar)); dic.put(new 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(new PdfName("Widths"), wd); if (fontDescriptor != null) dic.put(new PdfName("FontDescriptor"), fontDescriptor); return dic; } /** Outputs to the writer the font dictionaries and streams. * @param writer the writer for this document * @param ref the font indirect reference * @param params several parameters that depend on the font type * @throws IOException on error * @throws DocumentException error in generating the object */ void writeFont(PdfWriter writer, PdfIndirectReference ref, Object params[]) throws DocumentException, IOException { int firstChar = ((Integer)params[0]).intValue(); int lastChar = ((Integer)params[1]).intValue(); byte shortTag[] = (byte[])params[2]; if (!subset) { firstChar = 0; lastChar = shortTag.length - 1; for (int k = 0; k < shortTag.length; ++k) shortTag[k] = 1; } PdfIndirectReference ind_font = null; PdfObject pobj = null; PdfIndirectObject obj = null; String subsetPrefix = ""; if (embedded) { if (cff) { byte b[] = new byte[cffLength]; try { rf.reOpen(); rf.seek(cffOffset); rf.readFully(b); } finally { try { rf.close(); } catch (Exception e) { // empty on purpose } } pobj = new StreamFont(b, "Type1C"); obj = writer.addToBody(pobj); ind_font = obj.getIndirectReference(); } else { subsetPrefix = createSubsetPrefix(); HashMap glyphs = new HashMap(); for (int k = firstChar; k <= lastChar; ++k) { if (shortTag[k] != 0) { int metrics[]; if (fontSpecific) metrics = getMetricsTT(k); else metrics = getMetricsTT(unicodeDifferences[k]); if (metrics != null) glyphs.put(new Integer(metrics[0]), null); } } TrueTypeFontSubSet sb = new TrueTypeFontSubSet(fileName, rf, glyphs, directoryOffset, true); byte b[] = sb.process(); int lengths[] = new int[]{b.length}; pobj = new StreamFont(b, lengths); obj = writer.addToBody(pobj); ind_font = obj.getIndirectReference(); } } pobj = getFontDescriptor(ind_font, subsetPrefix); if (pobj != null){ obj = writer.addToBody(pobj); ind_font = obj.getIndirectReference(); } pobj = getFontBaseType(ind_font, subsetPrefix, firstChar, lastChar, shortTag); writer.addToBody(pobj, ref); } /** Gets the font parameter identified by <CODE>key</CODE>. Valid values * for <CODE>key</CODE> are <CODE>ASCENT</CODE>, <CODE>CAPHEIGHT</CODE>, <CODE>DESCENT</CODE> * and <CODE>ITALICANGLE</CODE>. * @param key the parameter to be extracted * @param fontSize the font size in points * @return the parameter in points */ public float getFontDescriptor(int key, float fontSize) { switch (key) { case ASCENT: return (float)os_2.sTypoAscender * fontSize / (float)head.unitsPerEm; case CAPHEIGHT: return (float)os_2.sCapHeight * fontSize / (float)head.unitsPerEm; case DESCENT: return (float)os_2.sTypoDescender * fontSize / (float)head.unitsPerEm; case ITALICANGLE: return (float)italicAngle; case BBOXLLX: return fontSize * (int)head.xMin / head.unitsPerEm; case BBOXLLY: return fontSize * (int)head.yMin / head.unitsPerEm; case BBOXURX: return fontSize * (int)head.xMax / head.unitsPerEm; case BBOXURY: return fontSize * (int)head.yMax / head.unitsPerEm; case AWT_ASCENT: return fontSize * (int)hhea.Ascender / head.unitsPerEm; case AWT_DESCENT: return fontSize * (int)hhea.Descender / head.unitsPerEm; case AWT_LEADING: return fontSize * (int)hhea.LineGap / head.unitsPerEm; case AWT_MAXADVANCE: return fontSize * (int)hhea.advanceWidthMax / head.unitsPerEm; } return 0; } /** Gets the glyph index and metrics for a character. * @param c the character * @return an <CODE>int</CODE> array with {glyph index, width} */ public int[] getMetricsTT(int c) { if (!fontSpecific && cmap31 != null) return (int[])cmap31.get(new Integer(c)); if (fontSpecific && cmap10 != null) return (int[])cmap10.get(new Integer(c)); return null; } /** Gets the postscript font name. * @return the postscript font name */ public String getPostscriptFontName() { return fontName; } /** Gets the code pages supported by the font. * @return the code pages supported by the font */ public String[] getCodePagesSupported() { long cp = (((long)os_2.ulCodePageRange2) << 32) + ((long)os_2.ulCodePageRange1 & 0xffffffffL); int count = 0; long bit = 1; for (int k = 0; k < 64; ++k) { if ((cp & bit) != 0 && codePages[k] != null) ++count; bit <<= 1; } String ret[] = new String[count]; count = 0; bit = 1; for (int k = 0; k < 64; ++k) { if ((cp & bit) != 0 && codePages[k] != null) ret[count++] = codePages[k]; bit <<= 1; } return ret; } /** Gets the full name of the font. If it is a True Type font * each array element will have {Platform ID, Platform Encoding ID, * Language ID, font name}. The interpretation of this values can be * found in the Open Type specification, chapter 2, in the 'name' table.<br> * For the other fonts the array has a single element with {"", "", "", * font name}. * @return the full name of the font */ public String[][] getFullFontName() { return fullName; } /** Gets the family name of the font. If it is a True Type font * each array element will have {Platform ID, Platform Encoding ID, * Language ID, font name}. The interpretation of this values can be * found in the Open Type specification, chapter 2, in the 'name' table.<br> * For the other fonts the array has a single element with {"", "", "", * font name}. * @return the family name of the font */ public String[][] getFamilyFontName() { return familyName; } /** Checks if the font has any kerning pairs. * @return <CODE>true</CODE> if the font has any kerning pairs */ public boolean hasKernPairs() { return kerning.size() > 0; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -