📄 truetypefont.java
字号:
return dic; } protected byte[] getFullFont() throws IOException { RandomAccessFileOrArray rf2 = null; try { rf2 = new RandomAccessFileOrArray(rf); rf2.reOpen(); byte b[] = new byte[rf2.length()]; rf2.readFully(b); return b; } finally { try {if (rf2 != null) {rf2.close();}} catch (Exception e) {} } } protected static int[] compactRanges(ArrayList ranges) { ArrayList simp = new ArrayList(); for (int k = 0; k < ranges.size(); ++k) { int[] r = (int[])ranges.get(k); for (int j = 0; j < r.length; j += 2) { simp.add(new int[]{Math.max(0, Math.min(r[j], r[j + 1])), Math.min(0xffff, Math.max(r[j], r[j + 1]))}); } } for (int k1 = 0; k1 < simp.size() - 1; ++k1) { for (int k2 = k1 + 1; k2 < simp.size(); ++k2) { int[] r1 = (int[])simp.get(k1); int[] r2 = (int[])simp.get(k2); if ((r1[0] >= r2[0] && r1[0] <= r2[1]) || (r1[1] >= r2[0] && r1[0] <= r2[1])) { r1[0] = Math.min(r1[0], r2[0]); r1[1] = Math.max(r1[1], r2[1]); simp.remove(k2); --k2; } } } int[] s = new int[simp.size() * 2]; for (int k = 0; k < simp.size(); ++k) { int[] r = (int[])simp.get(k); s[k * 2] = r[0]; s[k * 2 + 1] = r[1]; } return s; } protected void addRangeUni(HashMap longTag, boolean includeMetrics, boolean subsetp) { if (!subsetp && (subsetRanges != null || directoryOffset > 0)) { int[] rg = (subsetRanges == null && directoryOffset > 0) ? new int[]{0, 0xffff} : compactRanges(subsetRanges); HashMap usemap; if (!fontSpecific && cmap31 != null) usemap = cmap31; else if (fontSpecific && cmap10 != null) usemap = cmap10; else if (cmap31 != null) usemap = cmap31; else usemap = cmap10; for (Iterator it = usemap.entrySet().iterator(); it.hasNext();) { Map.Entry e = (Map.Entry)it.next(); int[] v = (int[])e.getValue(); Integer gi = new Integer(v[0]); if (longTag.containsKey(gi)) continue; int c = ((Integer)e.getKey()).intValue(); boolean skip = true; for (int k = 0; k < rg.length; k += 2) { if (c >= rg[k] && c <= rg[k + 1]) { skip = false; break; } } if (!skip) longTag.put(gi, includeMetrics ? new int[]{v[0], v[1], c} : null); } } } /** 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]; boolean subsetp = ((Boolean)params[3]).booleanValue() && subset; if (!subsetp) { 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) { pobj = new StreamFont(readCffFont(), "Type1C", compressionLevel); obj = writer.addToBody(pobj); ind_font = obj.getIndirectReference(); } else { if (subsetp) subsetPrefix = createSubsetPrefix(); HashMap glyphs = new HashMap(); for (int k = firstChar; k <= lastChar; ++k) { if (shortTag[k] != 0) { int[] metrics = null; if (specialMap != null) { int[] cd = GlyphList.nameToUnicode(differences[k]); if (cd != null) metrics = getMetricsTT(cd[0]); } else { if (fontSpecific) metrics = getMetricsTT(k); else metrics = getMetricsTT(unicodeDifferences[k]); } if (metrics != null) glyphs.put(new Integer(metrics[0]), null); } } addRangeUni(glyphs, false, subsetp); byte[] b = null; if (subsetp || directoryOffset != 0 || subsetRanges != null) { TrueTypeFontSubSet sb = new TrueTypeFontSubSet(fileName, new RandomAccessFileOrArray(rf), glyphs, directoryOffset, true, !subsetp); b = sb.process(); } else { b = getFullFont(); } int lengths[] = new int[]{b.length}; pobj = new StreamFont(b, lengths, compressionLevel); obj = writer.addToBody(pobj); ind_font = obj.getIndirectReference(); } } pobj = getFontDescriptor(ind_font, subsetPrefix, null); if (pobj != null){ obj = writer.addToBody(pobj); ind_font = obj.getIndirectReference(); } pobj = getFontBaseType(ind_font, subsetPrefix, firstChar, lastChar, shortTag); writer.addToBody(pobj, ref); } /** * If this font file is using the Compact Font File Format, then this method * will return the raw bytes needed for the font stream. If this method is * ever made public: make sure to add a test if (cff == true). * @return a byte array * @since 2.1.3 */ protected byte[] readCffFont() throws IOException { RandomAccessFileOrArray rf2 = new RandomAccessFileOrArray(rf); byte b[] = new byte[cffLength]; try { rf2.reOpen(); rf2.seek(cffOffset); rf2.readFully(b); } finally { try { rf2.close(); } catch (Exception e) { // empty on purpose } } return b; } /** * Returns a PdfStream object with the full font program. * @return a PdfStream with the font program * @since 2.1.3 */ public PdfStream getFullFontStream() throws IOException, DocumentException { if (cff) { return new StreamFont(readCffFont(), "Type1C", compressionLevel); } else { byte[] b = getFullFont(); int lengths[] = new int[]{b.length}; return new StreamFont(b, lengths, compressionLevel); } } /** 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 os_2.sTypoAscender * fontSize / head.unitsPerEm; case CAPHEIGHT: return os_2.sCapHeight * fontSize / head.unitsPerEm; case DESCENT: return os_2.sTypoDescender * fontSize / head.unitsPerEm; case ITALICANGLE: return (float)italicAngle; case BBOXLLX: return fontSize * head.xMin / head.unitsPerEm; case BBOXLLY: return fontSize * head.yMin / head.unitsPerEm; case BBOXURX: return fontSize * head.xMax / head.unitsPerEm; case BBOXURY: return fontSize * head.yMax / head.unitsPerEm; case AWT_ASCENT: return fontSize * hhea.Ascender / head.unitsPerEm; case AWT_DESCENT: return fontSize * hhea.Descender / head.unitsPerEm; case AWT_LEADING: return fontSize * hhea.LineGap / head.unitsPerEm; case AWT_MAXADVANCE: return fontSize * hhea.advanceWidthMax / head.unitsPerEm; case UNDERLINE_POSITION: return (underlinePosition - underlineThickness / 2) * fontSize / head.unitsPerEm; case UNDERLINE_THICKNESS: return underlineThickness * fontSize / head.unitsPerEm; case STRIKETHROUGH_POSITION: return os_2.yStrikeoutPosition * fontSize / head.unitsPerEm; case STRIKETHROUGH_THICKNESS: return os_2.yStrikeoutSize * fontSize / head.unitsPerEm; case SUBSCRIPT_SIZE: return os_2.ySubscriptYSize * fontSize / head.unitsPerEm; case SUBSCRIPT_OFFSET: return -os_2.ySubscriptYOffset * fontSize / head.unitsPerEm; case SUPERSCRIPT_SIZE: return os_2.ySuperscriptYSize * fontSize / head.unitsPerEm; case SUPERSCRIPT_OFFSET: return os_2.ySuperscriptYOffset * fontSize / 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 (cmapExt != null) return (int[])cmapExt.get(new Integer(c)); if (!fontSpecific && cmap31 != null) return (int[])cmap31.get(new Integer(c)); if (fontSpecific && cmap10 != null) return (int[])cmap10.get(new Integer(c)); if (cmap31 != null) return (int[])cmap31.get(new Integer(c)); if (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) + (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 all the entries of the Names-Table. If it is a True Type font * each array element will have {Name ID, 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[][] getAllNameEntries() { return allNameEntries; } /** 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; } /** * Sets the font name that will appear in the pdf font dictionary. * Use with care as it can easily make a font unreadable if not embedded. * @param name the new font name */ public void setPostscriptFontName(String name) { fontName = name; } /** * Sets the kerning between two Unicode chars. * @param char1 the first char * @param char2 the second char * @param kern the kerning to apply in normalized 1000 units * @return <code>true</code> if the kerning was applied, <code>false</code> otherwise */ public boolean setKerning(int char1, int char2, int kern) { int metrics[] = getMetricsTT(char1); if (metrics == null) return false; int c1 = metrics[0]; metrics = getMetricsTT(char2); if (metrics == null) return false; int c2 = metrics[0]; kerning.put((c1 << 16) + c2, kern); return true; } protected int[] getRawCharBBox(int c, String name) { HashMap map = null; if (name == null || cmap31 == null) map = cmap10; else map = cmap31; if (map == null) return null; int metric[] = (int[])map.get(new Integer(c)); if (metric == null || bboxes == null) return null; return bboxes[metric[0]]; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -