001: /*
002: * $Id: PDFFontEncoding.java,v 1.2 2007/12/20 18:33:31 rbair Exp $
003: *
004: * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005: * Santa Clara, California 95054, U.S.A. All rights reserved.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020: */
021:
022: package com.sun.pdfview.font;
023:
024: import java.io.IOException;
025: import java.util.ArrayList;
026: import java.util.HashMap;
027: import java.util.List;
028: import java.util.Map;
029:
030: import com.sun.pdfview.PDFObject;
031:
032: /**
033: * The PDFFont encoding encapsulates the mapping from character codes
034: * in the PDF document to glyphs of the font.
035: *
036: * Encodings take two basic forms. For Type1, TrueType, and Type3 fonts,
037: * the encoding maps from character codes to Strings, which represent the
038: * glyphs of the font. For Type0 fonts, the mapping is a CMap which maps
039: * character codes to characters in one of many descendant fonts.
040: *
041: * Note that the data in the PDF might be ASCII characters (bytes) or it might
042: * be a multi-byte format such as unicode. For now we will assume all
043: * glyph ids fit into at most the two bytes of a character.
044: */
045: public class PDFFontEncoding {
046:
047: /** Encoding types */
048: private static final int TYPE_ENCODING = 0;
049: private static final int TYPE_CMAP = 1;
050:
051: /**
052: * the base encoding (an array of integers which can be mapped to names
053: * using the methods on FontSupport
054: */
055: private int[] baseEncoding;
056:
057: /** any differences from the base encoding */
058: private Map differences;
059:
060: /**
061: * a CMap for fonts encoded by CMap
062: */
063: private PDFCMap cmap;
064:
065: /**
066: * the type of this encoding (encoding or CMap)
067: */
068: private int type;
069:
070: /** Creates a new instance of PDFFontEncoding */
071: public PDFFontEncoding(String fontType, PDFObject encoding)
072: throws IOException {
073: if (encoding.getType() == PDFObject.NAME) {
074: // if the encoding is a String, it is the name of an encoding
075: // or the name of a CMap, depending on the type of the font
076: if (fontType.equals("Type0")) {
077: type = TYPE_CMAP;
078: cmap = PDFCMap.getCMap(encoding.getStringValue());
079: } else {
080: type = TYPE_ENCODING;
081:
082: differences = new HashMap();
083: baseEncoding = this .getBaseEncoding(encoding
084: .getStringValue());
085: }
086: } else {
087: // loook at the "Type" entry of the encoding to determine the type
088: String typeStr = encoding.getDictRef("Type")
089: .getStringValue();
090:
091: if (typeStr.equals("Encoding")) {
092: // it is an encoding
093: type = TYPE_ENCODING;
094: parseEncoding(encoding);
095: } else if (typeStr.equals("CMap")) {
096: // it is a CMap
097: type = TYPE_CMAP;
098: cmap = PDFCMap.getCMap(encoding);
099: } else {
100: throw new IllegalArgumentException(
101: "Uknown encoding type: " + type);
102: }
103: }
104: }
105:
106: /** Get the glyphs associated with a given String */
107: public List getGlyphs(PDFFont font, String text) {
108: List outList = new ArrayList(text.length());
109:
110: // go character by character through the text
111: char[] arry = text.toCharArray();
112: for (int i = 0; i < arry.length; i++) {
113: switch (type) {
114: case TYPE_ENCODING:
115: outList.add(getGlyphFromEncoding(font, arry[i]));
116: break;
117: case TYPE_CMAP:
118: // 2 bytes -> 1 character in a CMap
119: char c = (char) ((arry[i] & 0xff) << 8);
120: if (i < arry.length - 1) {
121: c |= (char) (arry[++i] & 0xff);
122: }
123: outList.add(getGlyphFromCMap(font, c));
124: break;
125: }
126: }
127:
128: return outList;
129: }
130:
131: /**
132: * Get a glyph from an encoding, given a font and character
133: */
134: private PDFGlyph getGlyphFromEncoding(PDFFont font, char src) {
135: String charName = null;
136:
137: // only deal with one byte of source
138: src &= 0xff;
139:
140: // see if this character is in the differences list
141: if (differences.containsKey(new Character(src))) {
142: charName = (String) differences.get(new Character(src));
143: } else if (baseEncoding != null) {
144: // get the character name from the base encoding
145: int charID = baseEncoding[src];
146: charName = FontSupport.getName(charID);
147: }
148:
149: return font.getCachedGlyph(src, charName);
150: }
151:
152: /**
153: * Get a glyph from a CMap, given a Type0 font and a character
154: */
155: private PDFGlyph getGlyphFromCMap(PDFFont font, char src) {
156: int fontID = cmap.getFontID(src);
157: char charID = cmap.map(src);
158:
159: if (font instanceof Type0Font) {
160: font = ((Type0Font) font).getDescendantFont(fontID);
161: }
162:
163: return font.getCachedGlyph(charID, null);
164: }
165:
166: /**
167: * Parse a PDF encoding object for the actual encoding
168: */
169: public void parseEncoding(PDFObject encoding) throws IOException {
170: differences = new HashMap();
171:
172: // figure out the base encoding, if one exists
173: PDFObject baseEncObj = encoding.getDictRef("BaseEncoding");
174: if (baseEncObj != null) {
175: baseEncoding = getBaseEncoding(baseEncObj.getStringValue());
176: }
177:
178: // parse the differences array
179: PDFObject diffArrayObj = encoding.getDictRef("Differences");
180: if (diffArrayObj != null) {
181: PDFObject[] diffArray = diffArrayObj.getArray();
182: int curPosition = -1;
183:
184: for (int i = 0; i < diffArray.length; i++) {
185: if (diffArray[i].getType() == PDFObject.NUMBER) {
186: curPosition = diffArray[i].getIntValue();
187: } else if (diffArray[i].getType() == PDFObject.NAME) {
188: Character key = new Character((char) curPosition);
189: differences.put(key, diffArray[i].getStringValue());
190: curPosition++;
191: } else {
192: throw new IllegalArgumentException(
193: "Unexpected type in diff array: "
194: + diffArray[i]);
195: }
196: }
197: }
198: }
199:
200: /** Get the base encoding for a given name */
201: private int[] getBaseEncoding(String encodingName) {
202: if (encodingName.equals("MacRomanEncoding")) {
203: return FontSupport.macRomanEncoding;
204: } else if (encodingName.equals("MacExpertEncoding")) {
205: return FontSupport.type1CExpertCharset;
206: } else if (encodingName.equals("WinAnsiEncoding")) {
207: return FontSupport.winAnsiEncoding;
208: } else {
209: throw new IllegalArgumentException("Unknown encoding: "
210: + encodingName);
211: }
212: }
213: }
|