001: /*
002: * $Id: PDFFont.java,v 1.3 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: import com.sun.pdfview.PDFParseException;
032:
033: /**
034: * a Font definition for PDF files
035: * @author Mike Wessler
036: */
037: public abstract class PDFFont {
038: /** the font SubType of this font */
039: private String subtype;
040:
041: /** the postscript name of this font */
042: private String baseFont;
043:
044: /** the font encoding (maps character ids to glyphs) */
045: private PDFFontEncoding encoding;
046:
047: /** the font descriptor */
048: private PDFFontDescriptor descriptor;
049:
050: /** the CMap that maps this font to unicode values */
051: private PDFCMap unicodeMap;
052:
053: /** a cache of glyphs indexed by character */
054: private Map charCache;
055:
056: /**
057: * get the PDFFont corresponding to the font described in a PDFObject.
058: * The object is actually a dictionary containing the following keys:<br>
059: * Type = "Font"<br>
060: * Subtype = (Type1 | TrueType | Type3 | Type0 | MMType1 | CIDFontType0 |
061: * CIDFontType2)<br>
062: * FirstChar = #<br>
063: * LastChar = #<br>
064: * Widths = array of #<br>
065: * Encoding = (some name representing a dictionary in the resources | an
066: * inline dictionary)
067: * <p>
068: * For Type1 and TrueType fonts, the dictionary also contains:<br>
069: * BaseFont = (some name, or XXXXXX+Name as a subset of font Name)
070: * <p>
071: * For Type3 font, the dictionary contains:<br>
072: * FontBBox = (rectangle)<br>
073: * FontMatrix = (array, typically [0.001, 0, 0, 0.001, 0, 0])<br>
074: * CharProcs = (dictionary)
075: * Resources = (dictionary)
076: */
077: public synchronized static PDFFont getFont(PDFObject obj,
078: HashMap resources) throws IOException {
079: // the obj is actually a dictionary containing:
080: // Type (=Font)
081: // Subtype (Type1, TrueType, Type3, Type0, MMType1, CIDFontType0,2)
082: // FirstChar (int)
083: // LastChar (int)
084: // Widths (array)
085: // Encoding (name or dict) : assumes StandardEncoding
086: // and........
087: // Type1 and TrueType fonts:
088: // BaseFont (name) // may be XXXXXX+Fontname as a subset.
089: // FontDescriptor (dict)
090: // Type3 fonts:
091: // FontBBox (rectangle)
092: // FontMatrix (array) // e.g. [0.001 0 0 0.001 0 0]
093: // CharProcs (dict)
094: // Resources (dict)
095: //
096: // Font descriptor (Type1 and TrueType fonts):
097: // FontName (name)
098: // Flags (1=monospace, 2=serif, 4=script, 7=italic, 19=bold)
099: // FontBBox (rectangle)
100: // ItalicAngle (float)
101: // Ascent (float)
102: // Descent (float)
103: // CapHeight (float)
104: // StemV (float)
105: // FontFile (stream for Type1 fonts)
106: // FontFile2 (stream for TrueType fonts)
107: // FontFile3 (stream for CFF/Type1C fonts)
108: //
109: // Font data can be Type1, TrueType(native), or Type1C
110: PDFFont font = (PDFFont) obj.getCache();
111: if (font != null) {
112: return font;
113: }
114:
115: String baseFont = null;
116: PDFFontEncoding encoding = null;
117: PDFFontDescriptor descriptor = null;
118:
119: String type = obj.getDictRef("Subtype").getStringValue();
120: PDFObject baseFontObj = obj.getDictRef("BaseFont");
121: PDFObject encodingObj = obj.getDictRef("Encoding");
122: PDFObject descObj = obj.getDictRef("FontDescriptor");
123:
124: if (baseFontObj != null) {
125: baseFont = baseFontObj.getStringValue();
126: } else {
127: baseFontObj = obj.getDictRef("Name");
128:
129: if (baseFontObj != null) {
130: baseFont = baseFontObj.getStringValue();
131: }
132: }
133:
134: if (encodingObj != null) {
135: encoding = new PDFFontEncoding(type, encodingObj);
136: }
137:
138: if (descObj != null) {
139: descriptor = new PDFFontDescriptor(descObj);
140: } else {
141: descriptor = new PDFFontDescriptor(baseFont);
142: }
143:
144: if (type.equals("Type0")) {
145: font = new Type0Font(baseFont, obj, descriptor);
146: } else if (type.equals("Type1")) {
147: // load a type1 font
148: if (descriptor == null) {
149: // it's one of the built-in fonts
150: font = new BuiltinFont(baseFont, obj);
151: } else if (descriptor.getFontFile() != null) {
152: // it's a Type1 font, included.
153: font = new Type1Font(baseFont, obj, descriptor);
154: } else if (descriptor.getFontFile3() != null) {
155: // it's a CFF (Type1C) font
156: font = new Type1CFont(baseFont, obj, descriptor);
157: } else {
158: // no font info. Fake it based on the FontDescriptor
159: // System.out.println("Fakeout native font");
160: font = new BuiltinFont(baseFont, obj, descriptor);
161: }
162: } else if (type.equals("TrueType")) {
163: if (descriptor.getFontFile2() != null) {
164: // load a TrueType font
165: font = new TTFFont(baseFont, obj, descriptor);
166: } else {
167: // fake it with a built-in font
168: font = new BuiltinFont(baseFont, obj, descriptor);
169: }
170: } else if (type.equals("Type3")) {
171: // load a type 3 font
172: font = new Type3Font(baseFont, obj, resources, descriptor);
173: } else if (type.equals("CIDFontType2")) {
174: font = new CIDFontType2(baseFont, obj, descriptor);
175: } else if (type.equals("CIDFontType0")) {
176: font = new CIDFontType2(baseFont, obj, descriptor);
177: } else {
178: throw new PDFParseException("Don't know how to handle a '"
179: + type + "' font");
180: }
181:
182: font.setSubtype(type);
183: font.setEncoding(encoding);
184:
185: obj.setCache(font);
186: return font;
187: }
188:
189: /**
190: * Get the subtype of this font.
191: * @return the subtype, one of: Type0, Type1, TrueType or Type3
192: */
193: public String getSubtype() {
194: return subtype;
195: }
196:
197: /**
198: * Set the font subtype
199: */
200: public void setSubtype(String subtype) {
201: this .subtype = subtype;
202: }
203:
204: /**
205: * Get the postscript name of this font
206: * @return the postscript name of this font
207: */
208: public String getBaseFont() {
209: return baseFont;
210: }
211:
212: /**
213: * Set the postscript name of this font
214: * @param baseFont the postscript name of the font
215: */
216: public void setBaseFont(String baseFont) {
217: this .baseFont = baseFont;
218: }
219:
220: /**
221: * Get the encoding for this font
222: * @return the encoding which maps from this font to actual characters
223: */
224: public PDFFontEncoding getEncoding() {
225: return encoding;
226: }
227:
228: /**
229: * Set the encoding for this font
230: */
231: public void setEncoding(PDFFontEncoding encoding) {
232: this .encoding = encoding;
233: }
234:
235: /**
236: * Get the descriptor for this font
237: * @return the font descriptor
238: */
239: public PDFFontDescriptor getDescriptor() {
240: return descriptor;
241: }
242:
243: /**
244: * Set the descriptor font descriptor
245: */
246: public void setDescriptor(PDFFontDescriptor descriptor) {
247: this .descriptor = descriptor;
248: }
249:
250: /**
251: * Get the CMap which maps the characters in this font to unicode names
252: */
253: public PDFCMap getUnicodeMap() {
254: return unicodeMap;
255: }
256:
257: /**
258: * Set the CMap which maps the characters in this font to unicode names
259: */
260: public void setUnicodeMap(PDFCMap unicodeMap) {
261: this .unicodeMap = unicodeMap;
262: }
263:
264: /**
265: * Get the glyphs associated with a given String in this font
266: *
267: * @param text the text to translate into glyphs
268: */
269: public List getGlyphs(String text) {
270: List outList = null;
271:
272: // if we have an encoding, use it to get the commands
273: if (encoding != null) {
274: outList = encoding.getGlyphs(this , text);
275: } else {
276: // use the default mapping
277: char[] arry = text.toCharArray();
278: outList = new ArrayList(arry.length);
279:
280: for (int i = 0; i < arry.length; i++) {
281: // only look at 2 bytes when there is no encoding
282: char src = (char) (arry[i] & 0xff);
283: outList.add(getCachedGlyph(src, null));
284: }
285: }
286:
287: return outList;
288: }
289:
290: /**
291: * Get a glyph for a given character code. The glyph is returned
292: * from the cache if available, or added to the cache if not
293: *
294: * @param src the character code of this glyph
295: * @param name the name of the glyph, or null if the name is unknown
296: * @return a glyph for this character
297: */
298: public PDFGlyph getCachedGlyph(char src, String name) {
299: if (charCache == null) {
300: charCache = new HashMap();
301: }
302:
303: // try the cache
304: PDFGlyph glyph = (PDFGlyph) charCache.get(new Character(src));
305:
306: // if it's not there, add it to the cache
307: if (glyph == null) {
308: glyph = getGlyph(src, name);
309: charCache.put(new Character(src), glyph);
310: }
311:
312: return glyph;
313: }
314:
315: /**
316: * Create a PDFFont given the base font name and the font descriptor
317: * @param baseFont the postscript name of this font
318: * @param descriptor the descriptor for the font
319: */
320: protected PDFFont(String baseFont, PDFFontDescriptor descriptor) {
321: setBaseFont(baseFont);
322: setDescriptor(descriptor);
323: }
324:
325: /**
326: * Get the glyph for a given character code and name
327: *
328: * The preferred method of getting the glyph should be by name. If the
329: * name is null or not valid, then the character code should be used.
330: * If the both the code and the name are invalid, the undefined glyph
331: * should be returned.
332: *
333: * Note this method must *always* return a glyph.
334: *
335: * @param src the character code of this glyph
336: * @param name the name of this glyph or null if unknown
337: * @return a glyph for this character
338: */
339: protected abstract PDFGlyph getGlyph(char src, String name);
340:
341: /**
342: * Turn this font into a pretty String
343: */
344: @Override
345: public String toString() {
346: return getBaseFont();
347: }
348:
349: /**
350: * Compare two fonts base on the baseFont
351: */
352: @Override
353: public boolean equals(Object o) {
354: if (!(o instanceof PDFFont)) {
355: return false;
356: }
357:
358: return ((PDFFont) o).getBaseFont().equals(getBaseFont());
359: }
360:
361: /**
362: * Hash a font based on its base font
363: */
364: @Override
365: public int hashCode() {
366: return getBaseFont().hashCode();
367: }
368: }
|