0001: /*
0002: * $Id: BaseFont.java 2918 2007-09-09 12:21:32Z blowagie $
0003: * $Name$
0004: *
0005: * Copyright 2000-2006 by Paulo Soares.
0006: *
0007: * The contents of this file are subject to the Mozilla Public License Version 1.1
0008: * (the "License"); you may not use this file except in compliance with the License.
0009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the License.
0014: *
0015: * The Original Code is 'iText, a free JAVA-PDF library'.
0016: *
0017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0019: * All Rights Reserved.
0020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0022: *
0023: * Contributor(s): all the names of the contributors are added in the source code
0024: * where applicable.
0025: *
0026: * Alternatively, the contents of this file may be used under the terms of the
0027: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0028: * provisions of LGPL are applicable instead of those above. If you wish to
0029: * allow use of your version of this file only under the terms of the LGPL
0030: * License and not to allow others to use your version of this file under
0031: * the MPL, indicate your decision by deleting the provisions above and
0032: * replace them with the notice and other provisions required by the LGPL.
0033: * If you do not delete the provisions above, a recipient may use your version
0034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0035: *
0036: * This library is free software; you can redistribute it and/or modify it
0037: * under the terms of the MPL as stated above or under the terms of the GNU
0038: * Library General Public License as published by the Free Software Foundation;
0039: * either version 2 of the License, or any later version.
0040: *
0041: * This library is distributed in the hope that it will be useful, but WITHOUT
0042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0044: * details.
0045: *
0046: * If you didn't download this code from the following link, you should check if
0047: * you aren't using an obsolete version:
0048: * http://www.lowagie.com/iText/
0049: */
0050:
0051: package com.lowagie.text.pdf;
0052:
0053: import java.io.IOException;
0054: import java.io.InputStream;
0055: import java.util.ArrayList;
0056: import java.util.HashMap;
0057: import java.util.Iterator;
0058: import java.util.StringTokenizer;
0059:
0060: import com.lowagie.text.DocumentException;
0061:
0062: /**
0063: * Base class for the several font types supported
0064: *
0065: * @author Paulo Soares (psoares@consiste.pt)
0066: */
0067:
0068: public abstract class BaseFont {
0069:
0070: /** This is a possible value of a base 14 type 1 font */
0071: public static final String COURIER = "Courier";
0072:
0073: /** This is a possible value of a base 14 type 1 font */
0074: public static final String COURIER_BOLD = "Courier-Bold";
0075:
0076: /** This is a possible value of a base 14 type 1 font */
0077: public static final String COURIER_OBLIQUE = "Courier-Oblique";
0078:
0079: /** This is a possible value of a base 14 type 1 font */
0080: public static final String COURIER_BOLDOBLIQUE = "Courier-BoldOblique";
0081:
0082: /** This is a possible value of a base 14 type 1 font */
0083: public static final String HELVETICA = "Helvetica";
0084:
0085: /** This is a possible value of a base 14 type 1 font */
0086: public static final String HELVETICA_BOLD = "Helvetica-Bold";
0087:
0088: /** This is a possible value of a base 14 type 1 font */
0089: public static final String HELVETICA_OBLIQUE = "Helvetica-Oblique";
0090:
0091: /** This is a possible value of a base 14 type 1 font */
0092: public static final String HELVETICA_BOLDOBLIQUE = "Helvetica-BoldOblique";
0093:
0094: /** This is a possible value of a base 14 type 1 font */
0095: public static final String SYMBOL = "Symbol";
0096:
0097: /** This is a possible value of a base 14 type 1 font */
0098: public static final String TIMES_ROMAN = "Times-Roman";
0099:
0100: /** This is a possible value of a base 14 type 1 font */
0101: public static final String TIMES_BOLD = "Times-Bold";
0102:
0103: /** This is a possible value of a base 14 type 1 font */
0104: public static final String TIMES_ITALIC = "Times-Italic";
0105:
0106: /** This is a possible value of a base 14 type 1 font */
0107: public static final String TIMES_BOLDITALIC = "Times-BoldItalic";
0108:
0109: /** This is a possible value of a base 14 type 1 font */
0110: public static final String ZAPFDINGBATS = "ZapfDingbats";
0111:
0112: /** The maximum height above the baseline reached by glyphs in this
0113: * font, excluding the height of glyphs for accented characters.
0114: */
0115: public static final int ASCENT = 1;
0116: /** The y coordinate of the top of flat capital letters, measured from
0117: * the baseline.
0118: */
0119: public static final int CAPHEIGHT = 2;
0120: /** The maximum depth below the baseline reached by glyphs in this
0121: * font. The value is a negative number.
0122: */
0123: public static final int DESCENT = 3;
0124: /** The angle, expressed in degrees counterclockwise from the vertical,
0125: * of the dominant vertical strokes of the font. The value is
0126: * negative for fonts that slope to the right, as almost all italic fonts do.
0127: */
0128: public static final int ITALICANGLE = 4;
0129: /** The lower left x glyph coordinate.
0130: */
0131: public static final int BBOXLLX = 5;
0132: /** The lower left y glyph coordinate.
0133: */
0134: public static final int BBOXLLY = 6;
0135: /** The upper right x glyph coordinate.
0136: */
0137: public static final int BBOXURX = 7;
0138: /** The upper right y glyph coordinate.
0139: */
0140: public static final int BBOXURY = 8;
0141:
0142: /** java.awt.Font property */
0143: public static final int AWT_ASCENT = 9;
0144: /** java.awt.Font property */
0145: public static final int AWT_DESCENT = 10;
0146: /** java.awt.Font property */
0147: public static final int AWT_LEADING = 11;
0148: /** java.awt.Font property */
0149: public static final int AWT_MAXADVANCE = 12;
0150:
0151: /** The font is Type 1.
0152: */
0153: public static final int FONT_TYPE_T1 = 0;
0154: /** The font is True Type with a standard encoding.
0155: */
0156: public static final int FONT_TYPE_TT = 1;
0157: /** The font is CJK.
0158: */
0159: public static final int FONT_TYPE_CJK = 2;
0160: /** The font is True Type with a Unicode encoding.
0161: */
0162: public static final int FONT_TYPE_TTUNI = 3;
0163: /** A font already inside the document.
0164: */
0165: public static final int FONT_TYPE_DOCUMENT = 4;
0166: /** A Type3 font.
0167: */
0168: public static final int FONT_TYPE_T3 = 5;
0169: /** The Unicode encoding with horizontal writing.
0170: */
0171: public static final String IDENTITY_H = "Identity-H";
0172: /** The Unicode encoding with vertical writing.
0173: */
0174: public static final String IDENTITY_V = "Identity-V";
0175:
0176: /** A possible encoding. */
0177: public static final String CP1250 = "Cp1250";
0178:
0179: /** A possible encoding. */
0180: public static final String CP1252 = "Cp1252";
0181:
0182: /** A possible encoding. */
0183: public static final String CP1257 = "Cp1257";
0184:
0185: /** A possible encoding. */
0186: public static final String WINANSI = "Cp1252";
0187:
0188: /** A possible encoding. */
0189: public static final String MACROMAN = "MacRoman";
0190:
0191: public static final int[] CHAR_RANGE_LATIN = { 0, 0x17f, 0x2000,
0192: 0x206f, 0x20a0, 0x20cf, 0xfb00, 0xfb06 };
0193: public static final int[] CHAR_RANGE_ARABIC = { 0, 0x7f, 0x0600,
0194: 0x067f, 0x20a0, 0x20cf, 0xfb50, 0xfbff, 0xfe70, 0xfeff };
0195: public static final int[] CHAR_RANGE_HEBREW = { 0, 0x7f, 0x0590,
0196: 0x05ff, 0x20a0, 0x20cf, 0xfb1d, 0xfb4f };
0197: public static final int[] CHAR_RANGE_CYRILLIC = { 0, 0x7f, 0x0400,
0198: 0x052f, 0x2000, 0x206f, 0x20a0, 0x20cf };
0199:
0200: /** if the font has to be embedded */
0201: public static final boolean EMBEDDED = true;
0202:
0203: /** if the font doesn't have to be embedded */
0204: public static final boolean NOT_EMBEDDED = false;
0205: /** if the font has to be cached */
0206: public static final boolean CACHED = true;
0207: /** if the font doesn't have to be cached */
0208: public static final boolean NOT_CACHED = false;
0209:
0210: /** The path to the font resources. */
0211: public static final String RESOURCE_PATH = "com/lowagie/text/pdf/fonts/";
0212: /** The fake CID code that represents a newline. */
0213: public static final char CID_NEWLINE = '\u7fff';
0214:
0215: protected ArrayList subsetRanges;
0216: /** The font type.
0217: */
0218: int fontType;
0219: /** a not defined character in a custom PDF encoding */
0220: public static final String notdef = ".notdef";
0221:
0222: /** table of characters widths for this encoding */
0223: protected int widths[] = new int[256];
0224:
0225: /** encoding names */
0226: protected String differences[] = new String[256];
0227: /** same as differences but with the unicode codes */
0228: protected char unicodeDifferences[] = new char[256];
0229:
0230: protected int charBBoxes[][] = new int[256][];
0231: /** encoding used with this font */
0232: protected String encoding;
0233:
0234: /** true if the font is to be embedded in the PDF */
0235: protected boolean embedded;
0236:
0237: /**
0238: * true if the font must use it's built in encoding. In that case the
0239: * <CODE>encoding</CODE> is only used to map a char to the position inside
0240: * the font, not to the expected char name.
0241: */
0242: protected boolean fontSpecific = true;
0243:
0244: /** cache for the fonts already used. */
0245: protected static HashMap fontCache = new HashMap();
0246:
0247: /** list of the 14 built in fonts. */
0248: protected static final HashMap BuiltinFonts14 = new HashMap();
0249:
0250: /** Forces the output of the width array. Only matters for the 14
0251: * built-in fonts.
0252: */
0253: protected boolean forceWidthsOutput = false;
0254:
0255: /** Converts <CODE>char</CODE> directly to <CODE>byte</CODE>
0256: * by casting.
0257: */
0258: protected boolean directTextToByte = false;
0259:
0260: /** Indicates if all the glyphs and widths for that particular
0261: * encoding should be included in the document.
0262: */
0263: protected boolean subset = true;
0264:
0265: protected boolean fastWinansi = false;
0266:
0267: /**
0268: * Custom encodings use this map to key the Unicode character
0269: * to the single byte code.
0270: */
0271: protected IntHashtable specialMap;
0272:
0273: static {
0274: BuiltinFonts14.put(COURIER, PdfName.COURIER);
0275: BuiltinFonts14.put(COURIER_BOLD, PdfName.COURIER_BOLD);
0276: BuiltinFonts14.put(COURIER_BOLDOBLIQUE,
0277: PdfName.COURIER_BOLDOBLIQUE);
0278: BuiltinFonts14.put(COURIER_OBLIQUE, PdfName.COURIER_OBLIQUE);
0279: BuiltinFonts14.put(HELVETICA, PdfName.HELVETICA);
0280: BuiltinFonts14.put(HELVETICA_BOLD, PdfName.HELVETICA_BOLD);
0281: BuiltinFonts14.put(HELVETICA_BOLDOBLIQUE,
0282: PdfName.HELVETICA_BOLDOBLIQUE);
0283: BuiltinFonts14
0284: .put(HELVETICA_OBLIQUE, PdfName.HELVETICA_OBLIQUE);
0285: BuiltinFonts14.put(SYMBOL, PdfName.SYMBOL);
0286: BuiltinFonts14.put(TIMES_ROMAN, PdfName.TIMES_ROMAN);
0287: BuiltinFonts14.put(TIMES_BOLD, PdfName.TIMES_BOLD);
0288: BuiltinFonts14.put(TIMES_BOLDITALIC, PdfName.TIMES_BOLDITALIC);
0289: BuiltinFonts14.put(TIMES_ITALIC, PdfName.TIMES_ITALIC);
0290: BuiltinFonts14.put(ZAPFDINGBATS, PdfName.ZAPFDINGBATS);
0291: }
0292:
0293: /** Generates the PDF stream with the Type1 and Truetype fonts returning
0294: * a PdfStream.
0295: */
0296: static class StreamFont extends PdfStream {
0297:
0298: /** Generates the PDF stream with the Type1 and Truetype fonts returning
0299: * a PdfStream.
0300: * @param contents the content of the stream
0301: * @param lengths an array of int that describes the several lengths of each part of the font
0302: * @throws DocumentException error in the stream compression
0303: */
0304: public StreamFont(byte contents[], int lengths[])
0305: throws DocumentException {
0306: try {
0307: bytes = contents;
0308: put(PdfName.LENGTH, new PdfNumber(bytes.length));
0309: for (int k = 0; k < lengths.length; ++k) {
0310: put(new PdfName("Length" + (k + 1)), new PdfNumber(
0311: lengths[k]));
0312: }
0313: flateCompress();
0314: } catch (Exception e) {
0315: throw new DocumentException(e);
0316: }
0317: }
0318:
0319: /**
0320: * Generates the PDF stream for a font.
0321: * @param contents the content of a stream
0322: * @param subType the subtype of the font.
0323: * @throws DocumentException
0324: */
0325: public StreamFont(byte contents[], String subType)
0326: throws DocumentException {
0327: try {
0328: bytes = contents;
0329: put(PdfName.LENGTH, new PdfNumber(bytes.length));
0330: if (subType != null)
0331: put(PdfName.SUBTYPE, new PdfName(subType));
0332: flateCompress();
0333: } catch (Exception e) {
0334: throw new DocumentException(e);
0335: }
0336: }
0337: }
0338:
0339: /**
0340: *Creates new BaseFont
0341: */
0342: protected BaseFont() {
0343: }
0344:
0345: /**
0346: * Creates a new font. This font can be one of the 14 built in types,
0347: * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the
0348: * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier
0349: * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An
0350: * example would be "STSong-Light,Bold". Note that this modifiers do not work if
0351: * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1".
0352: * This would get the second font (indexes start at 0), in this case "MS PGothic".
0353: * <P>
0354: * The fonts are cached and if they already exist they are extracted from the cache,
0355: * not parsed again.
0356: * <P>
0357: * Besides the common encodings described by name, custom encodings
0358: * can also be made. These encodings will only work for the single byte fonts
0359: * Type1 and TrueType. The encoding string starts with a '#'
0360: * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list
0361: * of hex values representing the Unicode codes that compose that encoding.<br>
0362: * The "simple" encoding is recommended for TrueType fonts
0363: * as the "full" encoding risks not matching the character with the right glyph
0364: * if not done with care.<br>
0365: * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be
0366: * described by non standard names like the Tex math fonts. Each group of three elements
0367: * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character
0368: * used to access the glyph. The space must be assigned to character position 32 otherwise
0369: * text justification will not work.
0370: * <P>
0371: * Example for a "simple" encoding that includes the Unicode
0372: * character space, A, B and ecyrillic:
0373: * <PRE>
0374: * "# simple 32 0020 0041 0042 0454"
0375: * </PRE>
0376: * <P>
0377: * Example for a "full" encoding for a Type1 Tex font:
0378: * <PRE>
0379: * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
0380: * </PRE>
0381: * <P>
0382: * This method calls:<br>
0383: * <PRE>
0384: * createFont(name, encoding, embedded, true, null, null);
0385: * </PRE>
0386: * @param name the name of the font or it's location on file
0387: * @param encoding the encoding to be applied to this font
0388: * @param embedded true if the font is to be embedded in the PDF
0389: * @return returns a new font. This font may come from the cache
0390: * @throws DocumentException the font is invalid
0391: * @throws IOException the font file could not be read
0392: */
0393: public static BaseFont createFont(String name, String encoding,
0394: boolean embedded) throws DocumentException, IOException {
0395: return createFont(name, encoding, embedded, true, null, null);
0396: }
0397:
0398: /** Creates a new font. This font can be one of the 14 built in types,
0399: * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the
0400: * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier
0401: * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An
0402: * example would be "STSong-Light,Bold". Note that this modifiers do not work if
0403: * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1".
0404: * This would get the second font (indexes start at 0), in this case "MS PGothic".
0405: * <P>
0406: * The fonts may or may not be cached depending on the flag <CODE>cached</CODE>.
0407: * If the <CODE>byte</CODE> arrays are present the font will be
0408: * read from them instead of the name. A name is still required to identify
0409: * the font type.
0410: * <P>
0411: * Besides the common encodings described by name, custom encodings
0412: * can also be made. These encodings will only work for the single byte fonts
0413: * Type1 and TrueType. The encoding string starts with a '#'
0414: * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list
0415: * of hex values representing the Unicode codes that compose that encoding.<br>
0416: * The "simple" encoding is recommended for TrueType fonts
0417: * as the "full" encoding risks not matching the character with the right glyph
0418: * if not done with care.<br>
0419: * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be
0420: * described by non standard names like the Tex math fonts. Each group of three elements
0421: * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character
0422: * used to access the glyph. The space must be assigned to character position 32 otherwise
0423: * text justification will not work.
0424: * <P>
0425: * Example for a "simple" encoding that includes the Unicode
0426: * character space, A, B and ecyrillic:
0427: * <PRE>
0428: * "# simple 32 0020 0041 0042 0454"
0429: * </PRE>
0430: * <P>
0431: * Example for a "full" encoding for a Type1 Tex font:
0432: * <PRE>
0433: * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
0434: * </PRE>
0435: * @param name the name of the font or it's location on file
0436: * @param encoding the encoding to be applied to this font
0437: * @param embedded true if the font is to be embedded in the PDF
0438: * @param cached true if the font comes from the cache or is added to
0439: * the cache if new, false if the font is always created new
0440: * @param ttfAfm the true type font or the afm in a byte array
0441: * @param pfb the pfb in a byte array
0442: * @return returns a new font. This font may come from the cache but only if cached
0443: * is true, otherwise it will always be created new
0444: * @throws DocumentException the font is invalid
0445: * @throws IOException the font file could not be read
0446: */
0447: public static BaseFont createFont(String name, String encoding,
0448: boolean embedded, boolean cached, byte ttfAfm[], byte pfb[])
0449: throws DocumentException, IOException {
0450: return createFont(name, encoding, embedded, cached, ttfAfm,
0451: pfb, false);
0452: }
0453:
0454: /** Creates a new font. This font can be one of the 14 built in types,
0455: * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the
0456: * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier
0457: * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An
0458: * example would be "STSong-Light,Bold". Note that this modifiers do not work if
0459: * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1".
0460: * This would get the second font (indexes start at 0), in this case "MS PGothic".
0461: * <P>
0462: * The fonts may or may not be cached depending on the flag <CODE>cached</CODE>.
0463: * If the <CODE>byte</CODE> arrays are present the font will be
0464: * read from them instead of the name. A name is still required to identify
0465: * the font type.
0466: * <P>
0467: * Besides the common encodings described by name, custom encodings
0468: * can also be made. These encodings will only work for the single byte fonts
0469: * Type1 and TrueType. The encoding string starts with a '#'
0470: * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list
0471: * of hex values representing the Unicode codes that compose that encoding.<br>
0472: * The "simple" encoding is recommended for TrueType fonts
0473: * as the "full" encoding risks not matching the character with the right glyph
0474: * if not done with care.<br>
0475: * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be
0476: * described by non standard names like the Tex math fonts. Each group of three elements
0477: * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character
0478: * used to access the glyph. The space must be assigned to character position 32 otherwise
0479: * text justification will not work.
0480: * <P>
0481: * Example for a "simple" encoding that includes the Unicode
0482: * character space, A, B and ecyrillic:
0483: * <PRE>
0484: * "# simple 32 0020 0041 0042 0454"
0485: * </PRE>
0486: * <P>
0487: * Example for a "full" encoding for a Type1 Tex font:
0488: * <PRE>
0489: * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
0490: * </PRE>
0491: * @param name the name of the font or it's location on file
0492: * @param encoding the encoding to be applied to this font
0493: * @param embedded true if the font is to be embedded in the PDF
0494: * @param cached true if the font comes from the cache or is added to
0495: * the cache if new, false if the font is always created new
0496: * @param ttfAfm the true type font or the afm in a byte array
0497: * @param pfb the pfb in a byte array
0498: * @param noThrow if true will not throw an exception if the font is not recognized and will return null, if false will throw
0499: * an exception if the font is not recognized. Note that even if true an exception may be thrown in some circumstances.
0500: * This parameter is useful for FontFactory that may have to check many invalid font names before finding the right one
0501: * @return returns a new font. This font may come from the cache but only if cached
0502: * is true, otherwise it will always be created new
0503: * @throws DocumentException the font is invalid
0504: * @throws IOException the font file could not be read
0505: */
0506: public static BaseFont createFont(String name, String encoding,
0507: boolean embedded, boolean cached, byte ttfAfm[],
0508: byte pfb[], boolean noThrow) throws DocumentException,
0509: IOException {
0510: String nameBase = getBaseName(name);
0511: encoding = normalizeEncoding(encoding);
0512: boolean isBuiltinFonts14 = BuiltinFonts14.containsKey(name);
0513: boolean isCJKFont = isBuiltinFonts14 ? false : CJKFont
0514: .isCJKFont(nameBase, encoding);
0515: if (isBuiltinFonts14 || isCJKFont)
0516: embedded = false;
0517: else if (encoding.equals(IDENTITY_H)
0518: || encoding.equals(IDENTITY_V))
0519: embedded = true;
0520: BaseFont fontFound = null;
0521: BaseFont fontBuilt = null;
0522: String key = name + "\n" + encoding + "\n" + embedded;
0523: if (cached) {
0524: synchronized (fontCache) {
0525: fontFound = (BaseFont) fontCache.get(key);
0526: }
0527: if (fontFound != null)
0528: return fontFound;
0529: }
0530: if (isBuiltinFonts14 || name.toLowerCase().endsWith(".afm")
0531: || name.toLowerCase().endsWith(".pfm")) {
0532: fontBuilt = new Type1Font(name, encoding, embedded, ttfAfm,
0533: pfb);
0534: fontBuilt.fastWinansi = encoding.equals(CP1252);
0535: } else if (nameBase.toLowerCase().endsWith(".ttf")
0536: || nameBase.toLowerCase().endsWith(".otf")
0537: || nameBase.toLowerCase().indexOf(".ttc,") > 0) {
0538: if (encoding.equals(IDENTITY_H)
0539: || encoding.equals(IDENTITY_V))
0540: fontBuilt = new TrueTypeFontUnicode(name, encoding,
0541: embedded, ttfAfm);
0542: else {
0543: fontBuilt = new TrueTypeFont(name, encoding, embedded,
0544: ttfAfm);
0545: fontBuilt.fastWinansi = encoding.equals(CP1252);
0546: }
0547: } else if (isCJKFont)
0548: fontBuilt = new CJKFont(name, encoding, embedded);
0549: else if (noThrow)
0550: return null;
0551: else
0552: throw new DocumentException("Font '" + name + "' with '"
0553: + encoding + "' is not recognized.");
0554: if (cached) {
0555: synchronized (fontCache) {
0556: fontFound = (BaseFont) fontCache.get(key);
0557: if (fontFound != null)
0558: return fontFound;
0559: fontCache.put(key, fontBuilt);
0560: }
0561: }
0562: return fontBuilt;
0563: }
0564:
0565: /**
0566: * Creates a font based on an existing document font. The created font font may not
0567: * behave as expected, depending on the encoding or subset.
0568: * @param fontRef the reference to the document font
0569: * @return the font
0570: */
0571: public static BaseFont createFont(PRIndirectReference fontRef) {
0572: return new DocumentFont(fontRef);
0573: }
0574:
0575: /**
0576: * Gets the name without the modifiers Bold, Italic or BoldItalic.
0577: * @param name the full name of the font
0578: * @return the name without the modifiers Bold, Italic or BoldItalic
0579: */
0580: protected static String getBaseName(String name) {
0581: if (name.endsWith(",Bold"))
0582: return name.substring(0, name.length() - 5);
0583: else if (name.endsWith(",Italic"))
0584: return name.substring(0, name.length() - 7);
0585: else if (name.endsWith(",BoldItalic"))
0586: return name.substring(0, name.length() - 11);
0587: else
0588: return name;
0589: }
0590:
0591: /**
0592: * Normalize the encoding names. "winansi" is changed to "Cp1252" and
0593: * "macroman" is changed to "MacRoman".
0594: * @param enc the encoding to be normalized
0595: * @return the normalized encoding
0596: */
0597: protected static String normalizeEncoding(String enc) {
0598: if (enc.equals("winansi") || enc.equals(""))
0599: return CP1252;
0600: else if (enc.equals("macroman"))
0601: return MACROMAN;
0602: else
0603: return enc;
0604: }
0605:
0606: /**
0607: * Creates the <CODE>widths</CODE> and the <CODE>differences</CODE> arrays
0608: */
0609: protected void createEncoding() {
0610: if (encoding.startsWith("#")) {
0611: specialMap = new IntHashtable();
0612: StringTokenizer tok = new StringTokenizer(encoding
0613: .substring(1), " ,\t\n\r\f");
0614: if (tok.nextToken().equals("full")) {
0615: while (tok.hasMoreTokens()) {
0616: String order = tok.nextToken();
0617: String name = tok.nextToken();
0618: char uni = (char) Integer.parseInt(tok.nextToken(),
0619: 16);
0620: int orderK;
0621: if (order.startsWith("'"))
0622: orderK = (int) order.charAt(1);
0623: else
0624: orderK = Integer.parseInt(order);
0625: orderK %= 256;
0626: specialMap.put((int) uni, orderK);
0627: differences[orderK] = name;
0628: unicodeDifferences[orderK] = uni;
0629: widths[orderK] = getRawWidth((int) uni, name);
0630: charBBoxes[orderK] = getRawCharBBox((int) uni, name);
0631: }
0632: } else {
0633: int k = 0;
0634: if (tok.hasMoreTokens())
0635: k = Integer.parseInt(tok.nextToken());
0636: while (tok.hasMoreTokens() && k < 256) {
0637: String hex = tok.nextToken();
0638: int uni = Integer.parseInt(hex, 16) % 0x10000;
0639: String name = GlyphList.unicodeToName(uni);
0640: if (name != null) {
0641: specialMap.put(uni, k);
0642: differences[k] = name;
0643: unicodeDifferences[k] = (char) uni;
0644: widths[k] = getRawWidth(uni, name);
0645: charBBoxes[k] = getRawCharBBox(uni, name);
0646: ++k;
0647: }
0648: }
0649: }
0650: for (int k = 0; k < 256; ++k) {
0651: if (differences[k] == null) {
0652: differences[k] = notdef;
0653: }
0654: }
0655: } else if (fontSpecific) {
0656: for (int k = 0; k < 256; ++k) {
0657: widths[k] = getRawWidth(k, null);
0658: charBBoxes[k] = getRawCharBBox(k, null);
0659: }
0660: } else {
0661: String s;
0662: String name;
0663: char c;
0664: byte b[] = new byte[1];
0665: for (int k = 0; k < 256; ++k) {
0666: b[0] = (byte) k;
0667: s = PdfEncodings.convertToString(b, encoding);
0668: if (s.length() > 0) {
0669: c = s.charAt(0);
0670: } else {
0671: c = '?';
0672: }
0673: name = GlyphList.unicodeToName((int) c);
0674: if (name == null)
0675: name = notdef;
0676: differences[k] = name;
0677: unicodeDifferences[k] = c;
0678: widths[k] = getRawWidth((int) c, name);
0679: charBBoxes[k] = getRawCharBBox((int) c, name);
0680: }
0681: }
0682: }
0683:
0684: /**
0685: * Gets the width from the font according to the Unicode char <CODE>c</CODE>
0686: * or the <CODE>name</CODE>. If the <CODE>name</CODE> is null it's a symbolic font.
0687: * @param c the unicode char
0688: * @param name the glyph name
0689: * @return the width of the char
0690: */
0691: abstract int getRawWidth(int c, String name);
0692:
0693: /**
0694: * Gets the kerning between two Unicode chars.
0695: * @param char1 the first char
0696: * @param char2 the second char
0697: * @return the kerning to be applied in normalized 1000 units
0698: */
0699: public abstract int getKerning(char char1, char char2);
0700:
0701: /**
0702: * Sets the kerning between two Unicode chars.
0703: * @param char1 the first char
0704: * @param char2 the second char
0705: * @param kern the kerning to apply in normalized 1000 units
0706: * @return <code>true</code> if the kerning was applied, <code>false</code> otherwise
0707: */
0708: public abstract boolean setKerning(char char1, char char2, int kern);
0709:
0710: /**
0711: * Gets the width of a <CODE>char</CODE> in normalized 1000 units.
0712: * @param char1 the unicode <CODE>char</CODE> to get the width of
0713: * @return the width in normalized 1000 units
0714: */
0715: public int getWidth(char char1) {
0716: if (fastWinansi) {
0717: if (char1 < 128 || (char1 >= 160 && char1 <= 255))
0718: return widths[char1];
0719: else
0720: return widths[PdfEncodings.winansi.get(char1)];
0721: } else {
0722: int total = 0;
0723: byte mbytes[] = convertToBytes(char1);
0724: for (int k = 0; k < mbytes.length; ++k)
0725: total += widths[0xff & mbytes[k]];
0726: return total;
0727: }
0728: }
0729:
0730: /**
0731: * Gets the width of a <CODE>String</CODE> in normalized 1000 units.
0732: * @param text the <CODE>String</CODE> to get the witdth of
0733: * @return the width in normalized 1000 units
0734: */
0735: public int getWidth(String text) {
0736: int total = 0;
0737: if (fastWinansi) {
0738: int len = text.length();
0739: for (int k = 0; k < len; ++k) {
0740: char char1 = text.charAt(k);
0741: if (char1 < 128 || (char1 >= 160 && char1 <= 255))
0742: total += widths[char1];
0743: else
0744: total += widths[PdfEncodings.winansi.get(char1)];
0745: }
0746: return total;
0747: } else {
0748: byte mbytes[] = convertToBytes(text);
0749: for (int k = 0; k < mbytes.length; ++k)
0750: total += widths[0xff & mbytes[k]];
0751: }
0752: return total;
0753: }
0754:
0755: /**
0756: * Gets the descent of a <CODE>String</CODE> in normalized 1000 units. The descent will always be
0757: * less than or equal to zero even if all the characters have an higher descent.
0758: * @param text the <CODE>String</CODE> to get the descent of
0759: * @return the dexcent in normalized 1000 units
0760: */
0761: public int getDescent(String text) {
0762: int min = 0;
0763: char chars[] = text.toCharArray();
0764: for (int k = 0; k < chars.length; ++k) {
0765: int bbox[] = getCharBBox(chars[k]);
0766: if (bbox != null && bbox[1] < min)
0767: min = bbox[1];
0768: }
0769: return min;
0770: }
0771:
0772: /**
0773: * Gets the ascent of a <CODE>String</CODE> in normalized 1000 units. The ascent will always be
0774: * greater than or equal to zero even if all the characters have a lower ascent.
0775: * @param text the <CODE>String</CODE> to get the ascent of
0776: * @return the ascent in normalized 1000 units
0777: */
0778: public int getAscent(String text) {
0779: int max = 0;
0780: char chars[] = text.toCharArray();
0781: for (int k = 0; k < chars.length; ++k) {
0782: int bbox[] = getCharBBox(chars[k]);
0783: if (bbox != null && bbox[3] > max)
0784: max = bbox[3];
0785: }
0786: return max;
0787: }
0788:
0789: /**
0790: * Gets the descent of a <CODE>String</CODE> in points. The descent will always be
0791: * less than or equal to zero even if all the characters have an higher descent.
0792: * @param text the <CODE>String</CODE> to get the descent of
0793: * @param fontSize the size of the font
0794: * @return the dexcent in points
0795: */
0796: public float getDescentPoint(String text, float fontSize) {
0797: return (float) getDescent(text) * 0.001f * fontSize;
0798: }
0799:
0800: /**
0801: * Gets the ascent of a <CODE>String</CODE> in points. The ascent will always be
0802: * greater than or equal to zero even if all the characters have a lower ascent.
0803: * @param text the <CODE>String</CODE> to get the ascent of
0804: * @param fontSize the size of the font
0805: * @return the ascent in points
0806: */
0807: public float getAscentPoint(String text, float fontSize) {
0808: return (float) getAscent(text) * 0.001f * fontSize;
0809: }
0810:
0811: // ia>
0812:
0813: /**
0814: * Gets the width of a <CODE>String</CODE> in points taking kerning
0815: * into account.
0816: * @param text the <CODE>String</CODE> to get the witdth of
0817: * @param fontSize the font size
0818: * @return the width in points
0819: */
0820: public float getWidthPointKerned(String text, float fontSize) {
0821: float size = (float) getWidth(text) * 0.001f * fontSize;
0822: if (!hasKernPairs())
0823: return size;
0824: int len = text.length() - 1;
0825: int kern = 0;
0826: char c[] = text.toCharArray();
0827: for (int k = 0; k < len; ++k) {
0828: kern += getKerning(c[k], c[k + 1]);
0829: }
0830: return size + kern * 0.001f * fontSize;
0831: }
0832:
0833: /**
0834: * Gets the width of a <CODE>String</CODE> in points.
0835: * @param text the <CODE>String</CODE> to get the witdth of
0836: * @param fontSize the font size
0837: * @return the width in points
0838: */
0839: public float getWidthPoint(String text, float fontSize) {
0840: return (float) getWidth(text) * 0.001f * fontSize;
0841: }
0842:
0843: /**
0844: * Gets the width of a <CODE>char</CODE> in points.
0845: * @param char1 the <CODE>char</CODE> to get the witdth of
0846: * @param fontSize the font size
0847: * @return the width in points
0848: */
0849: public float getWidthPoint(char char1, float fontSize) {
0850: return getWidth(char1) * 0.001f * fontSize;
0851: }
0852:
0853: /**
0854: * Converts a <CODE>String</CODE> to a </CODE>byte</CODE> array according
0855: * to the font's encoding.
0856: * @param text the <CODE>String</CODE> to be converted
0857: * @return an array of <CODE>byte</CODE> representing the conversion according to the font's encoding
0858: */
0859: byte[] convertToBytes(String text) {
0860: if (directTextToByte)
0861: return PdfEncodings.convertToBytes(text, null);
0862: if (specialMap != null) {
0863: byte[] b = new byte[text.length()];
0864: int ptr = 0;
0865: int length = text.length();
0866: for (int k = 0; k < length; ++k) {
0867: char c = text.charAt(k);
0868: if (specialMap.containsKey((int) c))
0869: b[ptr++] = (byte) specialMap.get((int) c);
0870: }
0871: if (ptr < length) {
0872: byte[] b2 = new byte[ptr];
0873: System.arraycopy(b, 0, b2, 0, ptr);
0874: return b2;
0875: } else
0876: return b;
0877: }
0878: return PdfEncodings.convertToBytes(text, encoding);
0879: }
0880:
0881: /**
0882: * Converts a <CODE>char</CODE> to a </CODE>byte</CODE> array according
0883: * to the font's encoding.
0884: * @param char1 the <CODE>char</CODE> to be converted
0885: * @return an array of <CODE>byte</CODE> representing the conversion according to the font's encoding
0886: */
0887: byte[] convertToBytes(char char1) {
0888: if (directTextToByte)
0889: return PdfEncodings.convertToBytes(char1, null);
0890: if (specialMap != null) {
0891: if (specialMap.containsKey((int) char1))
0892: return new byte[] { (byte) specialMap.get((int) char1) };
0893: else
0894: return new byte[0];
0895: }
0896: return PdfEncodings.convertToBytes(char1, encoding);
0897: }
0898:
0899: /** Outputs to the writer the font dictionaries and streams.
0900: * @param writer the writer for this document
0901: * @param ref the font indirect reference
0902: * @param params several parameters that depend on the font type
0903: * @throws IOException on error
0904: * @throws DocumentException error in generating the object
0905: */
0906: abstract void writeFont(PdfWriter writer, PdfIndirectReference ref,
0907: Object params[]) throws DocumentException, IOException;
0908:
0909: /** Gets the encoding used to convert <CODE>String</CODE> into <CODE>byte[]</CODE>.
0910: * @return the encoding name
0911: */
0912: public String getEncoding() {
0913: return encoding;
0914: }
0915:
0916: /** Gets the font parameter identified by <CODE>key</CODE>. Valid values
0917: * for <CODE>key</CODE> are <CODE>ASCENT</CODE>, <CODE>AWT_ASCENT</CODE>, <CODE>CAPHEIGHT</CODE>,
0918: * <CODE>DESCENT</CODE>, <CODE>AWT_DESCENT</CODE>,
0919: * <CODE>ITALICANGLE</CODE>, <CODE>BBOXLLX</CODE>, <CODE>BBOXLLY</CODE>, <CODE>BBOXURX</CODE>
0920: * and <CODE>BBOXURY</CODE>.
0921: * @param key the parameter to be extracted
0922: * @param fontSize the font size in points
0923: * @return the parameter in points
0924: */
0925: public abstract float getFontDescriptor(int key, float fontSize);
0926:
0927: /** Gets the font type. The font types can be: FONT_TYPE_T1,
0928: * FONT_TYPE_TT, FONT_TYPE_CJK and FONT_TYPE_TTUNI.
0929: * @return the font type
0930: */
0931: public int getFontType() {
0932: return fontType;
0933: }
0934:
0935: /** Gets the embedded flag.
0936: * @return <CODE>true</CODE> if the font is embedded.
0937: */
0938: public boolean isEmbedded() {
0939: return embedded;
0940: }
0941:
0942: /** Gets the symbolic flag of the font.
0943: * @return <CODE>true</CODE> if the font is symbolic
0944: */
0945: public boolean isFontSpecific() {
0946: return fontSpecific;
0947: }
0948:
0949: /** Creates a unique subset prefix to be added to the font name when the font is embedded and subset.
0950: * @return the subset prefix
0951: */
0952: public static String createSubsetPrefix() {
0953: String s = "";
0954: for (int k = 0; k < 6; ++k)
0955: s += (char) (Math.random() * 26 + 'A');
0956: return s + "+";
0957: }
0958:
0959: /** Gets the Unicode character corresponding to the byte output to the pdf stream.
0960: * @param index the byte index
0961: * @return the Unicode character
0962: */
0963: char getUnicodeDifferences(int index) {
0964: return unicodeDifferences[index];
0965: }
0966:
0967: /** Gets the postscript font name.
0968: * @return the postscript font name
0969: */
0970: public abstract String getPostscriptFontName();
0971:
0972: /**
0973: * Sets the font name that will appear in the pdf font dictionary.
0974: * Use with care as it can easily make a font unreadable if not embedded.
0975: * @param name the new font name
0976: */
0977: public abstract void setPostscriptFontName(String name);
0978:
0979: /** Gets the full name of the font. If it is a True Type font
0980: * each array element will have {Platform ID, Platform Encoding ID,
0981: * Language ID, font name}. The interpretation of this values can be
0982: * found in the Open Type specification, chapter 2, in the 'name' table.<br>
0983: * For the other fonts the array has a single element with {"", "", "",
0984: * font name}.
0985: * @return the full name of the font
0986: */
0987: public abstract String[][] getFullFontName();
0988:
0989: /** Gets the full name of the font. If it is a True Type font
0990: * each array element will have {Platform ID, Platform Encoding ID,
0991: * Language ID, font name}. The interpretation of this values can be
0992: * found in the Open Type specification, chapter 2, in the 'name' table.<br>
0993: * For the other fonts the array has a single element with {"", "", "",
0994: * font name}.
0995: * @param name the name of the font
0996: * @param encoding the encoding of the font
0997: * @param ttfAfm the true type font or the afm in a byte array
0998: * @throws DocumentException on error
0999: * @throws IOException on error
1000: * @return the full name of the font
1001: */
1002: public static String[][] getFullFontName(String name,
1003: String encoding, byte ttfAfm[]) throws DocumentException,
1004: IOException {
1005: String nameBase = getBaseName(name);
1006: BaseFont fontBuilt = null;
1007: if (nameBase.toLowerCase().endsWith(".ttf")
1008: || nameBase.toLowerCase().endsWith(".otf")
1009: || nameBase.toLowerCase().indexOf(".ttc,") > 0)
1010: fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm,
1011: true);
1012: else
1013: fontBuilt = createFont(name, encoding, false, false,
1014: ttfAfm, null);
1015: return fontBuilt.getFullFontName();
1016: }
1017:
1018: /** Gets all the names from the font. Only the required tables are read.
1019: * @param name the name of the font
1020: * @param encoding the encoding of the font
1021: * @param ttfAfm the true type font or the afm in a byte array
1022: * @throws DocumentException on error
1023: * @throws IOException on error
1024: * @return an array of Object[] built with {getPostscriptFontName(), getFamilyFontName(), getFullFontName()}
1025: */
1026: public static Object[] getAllFontNames(String name,
1027: String encoding, byte ttfAfm[]) throws DocumentException,
1028: IOException {
1029: String nameBase = getBaseName(name);
1030: BaseFont fontBuilt = null;
1031: if (nameBase.toLowerCase().endsWith(".ttf")
1032: || nameBase.toLowerCase().endsWith(".otf")
1033: || nameBase.toLowerCase().indexOf(".ttc,") > 0)
1034: fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm,
1035: true);
1036: else
1037: fontBuilt = createFont(name, encoding, false, false,
1038: ttfAfm, null);
1039: return new Object[] { fontBuilt.getPostscriptFontName(),
1040: fontBuilt.getFamilyFontName(),
1041: fontBuilt.getFullFontName() };
1042: }
1043:
1044: /** Gets the family name of the font. If it is a True Type font
1045: * each array element will have {Platform ID, Platform Encoding ID,
1046: * Language ID, font name}. The interpretation of this values can be
1047: * found in the Open Type specification, chapter 2, in the 'name' table.<br>
1048: * For the other fonts the array has a single element with {"", "", "",
1049: * font name}.
1050: * @return the family name of the font
1051: */
1052: public abstract String[][] getFamilyFontName();
1053:
1054: /** Gets the code pages supported by the font. This has only meaning
1055: * with True Type fonts.
1056: * @return the code pages supported by the font
1057: */
1058: public String[] getCodePagesSupported() {
1059: return new String[0];
1060: }
1061:
1062: /** Enumerates the postscript font names present inside a
1063: * True Type Collection.
1064: * @param ttcFile the file name of the font
1065: * @throws DocumentException on error
1066: * @throws IOException on error
1067: * @return the postscript font names
1068: */
1069: public static String[] enumerateTTCNames(String ttcFile)
1070: throws DocumentException, IOException {
1071: return new EnumerateTTC(ttcFile).getNames();
1072: }
1073:
1074: /** Enumerates the postscript font names present inside a
1075: * True Type Collection.
1076: * @param ttcArray the font as a <CODE>byte</CODE> array
1077: * @throws DocumentException on error
1078: * @throws IOException on error
1079: * @return the postscript font names
1080: */
1081: public static String[] enumerateTTCNames(byte ttcArray[])
1082: throws DocumentException, IOException {
1083: return new EnumerateTTC(ttcArray).getNames();
1084: }
1085:
1086: /** Gets the font width array.
1087: * @return the font width array
1088: */
1089: public int[] getWidths() {
1090: return widths;
1091: }
1092:
1093: /** Gets the array with the names of the characters.
1094: * @return the array with the names of the characters
1095: */
1096: public String[] getDifferences() {
1097: return differences;
1098: }
1099:
1100: /** Gets the array with the unicode characters.
1101: * @return the array with the unicode characters
1102: */
1103: public char[] getUnicodeDifferences() {
1104: return unicodeDifferences;
1105: }
1106:
1107: /** Gets the state of the property.
1108: * @return value of property forceWidthsOutput
1109: */
1110: public boolean isForceWidthsOutput() {
1111: return forceWidthsOutput;
1112: }
1113:
1114: /** Set to <CODE>true</CODE> to force the generation of the
1115: * widths array.
1116: * @param forceWidthsOutput <CODE>true</CODE> to force the generation of the
1117: * widths array
1118: */
1119: public void setForceWidthsOutput(boolean forceWidthsOutput) {
1120: this .forceWidthsOutput = forceWidthsOutput;
1121: }
1122:
1123: /** Gets the direct conversion of <CODE>char</CODE> to <CODE>byte</CODE>.
1124: * @return value of property directTextToByte.
1125: * @see #setDirectTextToByte(boolean directTextToByte)
1126: */
1127: public boolean isDirectTextToByte() {
1128: return directTextToByte;
1129: }
1130:
1131: /** Sets the conversion of <CODE>char</CODE> directly to <CODE>byte</CODE>
1132: * by casting. This is a low level feature to put the bytes directly in
1133: * the content stream without passing through String.getBytes().
1134: * @param directTextToByte New value of property directTextToByte.
1135: */
1136: public void setDirectTextToByte(boolean directTextToByte) {
1137: this .directTextToByte = directTextToByte;
1138: }
1139:
1140: /** Indicates if all the glyphs and widths for that particular
1141: * encoding should be included in the document.
1142: * @return <CODE>false</CODE> to include all the glyphs and widths.
1143: */
1144: public boolean isSubset() {
1145: return subset;
1146: }
1147:
1148: /** Indicates if all the glyphs and widths for that particular
1149: * encoding should be included in the document. When set to <CODE>true</CODE>
1150: * only the glyphs used will be included in the font. When set to <CODE>false</CODE>
1151: * and {@link #addSubsetRange(int[])} was not called the full font will be included
1152: * otherwise just the characters ranges will be included.
1153: * @param subset new value of property subset
1154: */
1155: public void setSubset(boolean subset) {
1156: this .subset = subset;
1157: }
1158:
1159: /** Gets the font resources.
1160: * @param key the full name of the resource
1161: * @return the <CODE>InputStream</CODE> to get the resource or
1162: * <CODE>null</CODE> if not found
1163: */
1164: public static InputStream getResourceStream(String key) {
1165: return getResourceStream(key, null);
1166: }
1167:
1168: /** Gets the font resources.
1169: * @param key the full name of the resource
1170: * @param loader the ClassLoader to load the resource or null to try the ones available
1171: * @return the <CODE>InputStream</CODE> to get the resource or
1172: * <CODE>null</CODE> if not found
1173: */
1174: public static InputStream getResourceStream(String key,
1175: ClassLoader loader) {
1176: if (key.startsWith("/"))
1177: key = key.substring(1);
1178: InputStream is = null;
1179: if (loader != null) {
1180: is = loader.getResourceAsStream(key);
1181: if (is != null)
1182: return is;
1183: }
1184: // Try to use Context Class Loader to load the properties file.
1185: try {
1186: java.lang.reflect.Method getCCL = Thread.class.getMethod(
1187: "getContextClassLoader", new Class[0]);
1188: if (getCCL != null) {
1189: ClassLoader contextClassLoader = (ClassLoader) getCCL
1190: .invoke(Thread.currentThread(), new Object[0]);
1191: if (contextClassLoader != null)
1192: is = contextClassLoader.getResourceAsStream(key);
1193: }
1194: } catch (Throwable e) {
1195: }
1196:
1197: if (is == null) {
1198: is = BaseFont.class.getResourceAsStream("/" + key);
1199: }
1200: if (is == null) {
1201: is = ClassLoader.getSystemResourceAsStream(key);
1202: }
1203: return is;
1204: }
1205:
1206: /** Gets the Unicode equivalent to a CID.
1207: * The (inexistent) CID <FF00> is translated as '\n'.
1208: * It has only meaning with CJK fonts with Identity encoding.
1209: * @param c the CID code
1210: * @return the Unicode equivalent
1211: */
1212: public char getUnicodeEquivalent(char c) {
1213: return c;
1214: }
1215:
1216: /** Gets the CID code given an Unicode.
1217: * It has only meaning with CJK fonts.
1218: * @param c the Unicode
1219: * @return the CID equivalent
1220: */
1221: public char getCidCode(char c) {
1222: return c;
1223: }
1224:
1225: /** Checks if the font has any kerning pairs.
1226: * @return <CODE>true</CODE> if the font has any kerning pairs
1227: */
1228: public abstract boolean hasKernPairs();
1229:
1230: /**
1231: * Checks if a character exists in this font.
1232: * @param c the character to check
1233: * @return <CODE>true</CODE> if the character has a glyph,
1234: * <CODE>false</CODE> otherwise
1235: */
1236: public boolean charExists(char c) {
1237: byte b[] = convertToBytes(c);
1238: return b.length > 0;
1239: }
1240:
1241: /**
1242: * Sets the character advance.
1243: * @param c the character
1244: * @param advance the character advance normalized to 1000 units
1245: * @return <CODE>true</CODE> if the advance was set,
1246: * <CODE>false</CODE> otherwise
1247: */
1248: public boolean setCharAdvance(char c, int advance) {
1249: byte b[] = convertToBytes(c);
1250: if (b.length == 0)
1251: return false;
1252: widths[0xff & b[0]] = advance;
1253: return true;
1254: }
1255:
1256: private static void addFont(PRIndirectReference fontRef,
1257: IntHashtable hits, ArrayList fonts) {
1258: PdfObject obj = PdfReader.getPdfObject(fontRef);
1259: if (obj == null || !obj.isDictionary())
1260: return;
1261: PdfDictionary font = (PdfDictionary) obj;
1262: PdfName subtype = (PdfName) PdfReader.getPdfObject(font
1263: .get(PdfName.SUBTYPE));
1264: if (!PdfName.TYPE1.equals(subtype)
1265: && !PdfName.TRUETYPE.equals(subtype))
1266: return;
1267: PdfName name = (PdfName) PdfReader.getPdfObject(font
1268: .get(PdfName.BASEFONT));
1269: fonts.add(new Object[] { PdfName.decodeName(name.toString()),
1270: fontRef });
1271: hits.put(fontRef.getNumber(), 1);
1272: }
1273:
1274: private static void recourseFonts(PdfDictionary page,
1275: IntHashtable hits, ArrayList fonts, int level) {
1276: ++level;
1277: if (level > 50) // in case we have an endless loop
1278: return;
1279: PdfDictionary resources = (PdfDictionary) PdfReader
1280: .getPdfObject(page.get(PdfName.RESOURCES));
1281: if (resources == null)
1282: return;
1283: PdfDictionary font = (PdfDictionary) PdfReader
1284: .getPdfObject(resources.get(PdfName.FONT));
1285: if (font != null) {
1286: for (Iterator it = font.getKeys().iterator(); it.hasNext();) {
1287: PdfObject ft = font.get((PdfName) it.next());
1288: if (ft == null || !ft.isIndirect())
1289: continue;
1290: int hit = ((PRIndirectReference) ft).getNumber();
1291: if (hits.containsKey(hit))
1292: continue;
1293: addFont((PRIndirectReference) ft, hits, fonts);
1294: }
1295: }
1296: PdfDictionary xobj = (PdfDictionary) PdfReader
1297: .getPdfObject(resources.get(PdfName.XOBJECT));
1298: if (xobj != null) {
1299: for (Iterator it = xobj.getKeys().iterator(); it.hasNext();) {
1300: recourseFonts((PdfDictionary) PdfReader
1301: .getPdfObject(xobj.get((PdfName) it.next())),
1302: hits, fonts, level);
1303: }
1304: }
1305: }
1306:
1307: /**
1308: * Gets a list of all document fonts. Each element of the <CODE>ArrayList</CODE>
1309: * contains a <CODE>Object[]{String,PRIndirectReference}</CODE> with the font name
1310: * and the indirect reference to it.
1311: * @param reader the document where the fonts are to be listed from
1312: * @return the list of fonts and references
1313: */
1314: public static ArrayList getDocumentFonts(PdfReader reader) {
1315: IntHashtable hits = new IntHashtable();
1316: ArrayList fonts = new ArrayList();
1317: int npages = reader.getNumberOfPages();
1318: for (int k = 1; k <= npages; ++k)
1319: recourseFonts(reader.getPageN(k), hits, fonts, 1);
1320: return fonts;
1321: }
1322:
1323: /**
1324: * Gets a list of the document fonts in a particular page. Each element of the <CODE>ArrayList</CODE>
1325: * contains a <CODE>Object[]{String,PRIndirectReference}</CODE> with the font name
1326: * and the indirect reference to it.
1327: * @param reader the document where the fonts are to be listed from
1328: * @param page the page to list the fonts from
1329: * @return the list of fonts and references
1330: */
1331: public static ArrayList getDocumentFonts(PdfReader reader, int page) {
1332: IntHashtable hits = new IntHashtable();
1333: ArrayList fonts = new ArrayList();
1334: recourseFonts(reader.getPageN(page), hits, fonts, 1);
1335: return fonts;
1336: }
1337:
1338: /**
1339: * Gets the smallest box enclosing the character contours. It will return
1340: * <CODE>null</CODE> if the font has not the information or the character has no
1341: * contours, as in the case of the space, for example. Characters with no contours may
1342: * also return [0,0,0,0].
1343: * @param c the character to get the contour bounding box from
1344: * @return an array of four floats with the bounding box in the format [llx,lly,urx,ury] or
1345: * <code>null</code>
1346: */
1347: public int[] getCharBBox(char c) {
1348: byte b[] = convertToBytes(c);
1349: if (b.length == 0)
1350: return null;
1351: else
1352: return charBBoxes[b[0] & 0xff];
1353: }
1354:
1355: protected abstract int[] getRawCharBBox(int c, String name);
1356:
1357: /**
1358: * iText expects Arabic Diactrics (tashkeel) to have zero advance but some fonts,
1359: * most notably those that come with Windows, like times.ttf, have non-zero
1360: * advance for those characters. This method makes those character to have zero
1361: * width advance and work correctly in the iText Arabic shaping and reordering
1362: * context.
1363: */
1364: public void correctArabicAdvance() {
1365: for (char c = '\u064b'; c <= '\u0658'; ++c)
1366: setCharAdvance(c, 0);
1367: setCharAdvance('\u0670', 0);
1368: for (char c = '\u06d6'; c <= '\u06dc'; ++c)
1369: setCharAdvance(c, 0);
1370: for (char c = '\u06df'; c <= '\u06e4'; ++c)
1371: setCharAdvance(c, 0);
1372: for (char c = '\u06e7'; c <= '\u06e8'; ++c)
1373: setCharAdvance(c, 0);
1374: for (char c = '\u06ea'; c <= '\u06ed'; ++c)
1375: setCharAdvance(c, 0);
1376: }
1377:
1378: /**
1379: * Adds a character range when subsetting. The range is an <CODE>int</CODE> array
1380: * where the first element is the start range inclusive and the second element is the
1381: * end range inclusive. Several ranges are allowed in the same array.
1382: * @param range the character range
1383: */
1384: public void addSubsetRange(int[] range) {
1385: if (subsetRanges == null)
1386: subsetRanges = new ArrayList();
1387: subsetRanges.add(range);
1388: }
1389: }
|