KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fonts > type1 > PFMFile


1 /*
2  * $Id: PFMFile.java,v 1.1.2.3 2003/02/25 13:13:21 jeremias Exp $
3  * ============================================================================
4  * The Apache Software License, Version 1.1
5  * ============================================================================
6  *
7  * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modifica-
10  * tion, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if any, must
20  * include the following acknowledgment: "This product includes software
21  * developed by the Apache Software Foundation (http://www.apache.org/)."
22  * Alternately, this acknowledgment may appear in the software itself, if
23  * and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "FOP" and "Apache Software Foundation" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * apache@apache.org.
29  *
30  * 5. Products derived from this software may not be called "Apache", nor may
31  * "Apache" appear in their name, without prior written permission of the
32  * Apache Software Foundation.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  * ============================================================================
45  *
46  * This software consists of voluntary contributions made by many individuals
47  * on behalf of the Apache Software Foundation and was originally created by
48  * James Tauber <jtauber@jtauber.com>. For more information on the Apache
49  * Software Foundation, please see <http://www.apache.org/>.
50  */

51 package org.apache.fop.fonts.type1;
52
53 import java.io.*;
54 import java.util.Map JavaDoc;
55
56 import org.apache.avalon.framework.logger.AbstractLogEnabled;
57
58 import org.apache.fop.fonts.Glyphs;
59
60 /**
61  * This class represents a PFM file (or parts of it) as a Java object.
62  */

63 public class PFMFile extends AbstractLogEnabled {
64
65     // Header stuff
66
private String JavaDoc windowsName;
67     private String JavaDoc postscriptName;
68     private short dfItalic;
69     private int dfWeight;
70     private short dfCharSet;
71     private short dfPitchAndFamily;
72     private int dfAvgWidth;
73     private int dfMaxWidth;
74     private int dfMinWidth;
75     private short dfFirstChar;
76     private short dfLastChar;
77
78     // Extension stuff
79
// ---
80

81     // Extend Text Metrics
82
private int etmCapHeight;
83     private int etmXHeight;
84     private int etmLowerCaseAscent;
85     private int etmLowerCaseDescent;
86
87     // Extent table
88
private int[] extentTable;
89
90     private Map JavaDoc kerningTab = new java.util.HashMap JavaDoc();
91
92     /**
93      * Parses a PFM file
94      *
95      * @param inStream The stream from which to read the PFM file.
96      */

97     public void load(InputStream inStream) throws IOException {
98         InputStream bufin = new BufferedInputStream(inStream, 1024);
99         bufin.mark(1024);
100         PFMInputStream in = new PFMInputStream(bufin);
101         int version = in.readShort();
102         long filesize = in.readInt();
103         bufin.reset();
104
105         byte[] buf = new byte[(int)filesize];
106         bufin.read(buf, 0, (int)filesize);
107
108         bufin = new ByteArrayInputStream(buf);
109         in = new PFMInputStream(bufin);
110         loadHeader(in);
111         loadExtension(in);
112     }
113
114     /**
115      * Parses the header of the PFM file.
116      *
117      * @param inStream The stream from which to read the PFM file.
118      */

119     private void loadHeader(PFMInputStream inStream) throws IOException {
120         inStream.skip(80);
121         dfItalic = inStream.readByte();
122         inStream.skip(2);
123         dfWeight = inStream.readShort();
124         dfCharSet = inStream.readByte();
125         inStream.skip(4);
126         dfPitchAndFamily = inStream.readByte();
127         dfAvgWidth = inStream.readShort();
128         dfMaxWidth = inStream.readShort();
129         dfFirstChar = inStream.readByte();
130         dfLastChar = inStream.readByte();
131         inStream.skip(8);
132         long faceOffset = inStream.readInt();
133
134         inStream.reset();
135         inStream.skip(faceOffset);
136         windowsName = inStream.readString();
137
138         inStream.reset();
139         inStream.skip(117);
140     }
141
142     /**
143      * Parses the extension part of the PFM file.
144      *
145      * @param inStream The stream from which to read the PFM file.
146      */

147     private void loadExtension(PFMInputStream inStream) throws IOException {
148         int size = inStream.readShort();
149         long extMetricsOffset = inStream.readInt();
150         long extentTableOffset = inStream.readInt();
151         inStream.skip(4);
152         long kernPairOffset = inStream.readInt();
153         long kernTrackOffset = inStream.readInt();
154         long driverInfoOffset = inStream.readInt();
155
156         if (kernPairOffset > 0) {
157             inStream.reset();
158             inStream.skip(kernPairOffset);
159             loadKernPairs(inStream);
160         }
161
162         inStream.reset();
163         inStream.skip(driverInfoOffset);
164         postscriptName = inStream.readString();
165
166         if (extMetricsOffset != 0) {
167             inStream.reset();
168             inStream.skip(extMetricsOffset);
169             loadExtMetrics(inStream);
170         }
171         if (extentTableOffset != 0) {
172             inStream.reset();
173             inStream.skip(extentTableOffset);
174             loadExtentTable(inStream);
175         }
176
177     }
178
179     /**
180      * Parses the kernPairs part of the pfm file
181      *
182      * @param inStream The stream from which to read the PFM file.
183      */

184     private void loadKernPairs(PFMInputStream inStream) throws IOException {
185         int i = inStream.readShort();
186
187         getLogger().info(i + " kerning pairs");
188         while (i > 0) {
189             int g1 = (int)inStream.readByte();
190             i--;
191             int g2 = (int)inStream.readByte();
192             getLogger().debug("Char no: (" + g1 + ", " + g2 + ") kern");
193
194             int adj = inStream.readShort();
195             if (adj > 0x8000) {
196                 adj = -(0x10000 - adj);
197                 getLogger().debug("adjust: " + adj);
198             }
199
200             if (getLogger().isDebugEnabled()) {
201                 String JavaDoc glyph1 = Glyphs.tex8r[g1];
202                 String JavaDoc glyph2 = Glyphs.tex8r[g2];
203                 getLogger().debug("glyphs: " + glyph1 + ", " + glyph2);
204             }
205
206             Map JavaDoc adjTab = (Map JavaDoc)kerningTab.get(new Integer JavaDoc(g1));
207             if (adjTab == null) {
208                 adjTab = new java.util.HashMap JavaDoc();
209             }
210             adjTab.put(new Integer JavaDoc(g2), new Integer JavaDoc(adj));
211             kerningTab.put(new Integer JavaDoc(g1), adjTab);
212         }
213     }
214
215     /**
216      * Parses the extended metrics part of the PFM file.
217      *
218      * @param inStream The stream from which to read the PFM file.
219      */

220     private void loadExtMetrics(PFMInputStream inStream) throws IOException {
221         int size = inStream.readShort();
222         inStream.skip(12);
223         etmCapHeight = inStream.readShort();
224         etmXHeight = inStream.readShort();
225         etmLowerCaseAscent = inStream.readShort();
226         etmLowerCaseDescent = inStream.readShort();
227     }
228
229     /**
230      * Parses the extent table of the PFM file.
231      *
232      * @param inStream The stream from which to read the PFM file.
233      */

234     private void loadExtentTable(PFMInputStream inStream) throws IOException {
235         extentTable = new int[dfLastChar - dfFirstChar + 1];
236         dfMinWidth = dfMaxWidth;
237         for (short i = dfFirstChar; i <= dfLastChar; i++) {
238             extentTable[i - dfFirstChar] = inStream.readShort();
239             if (extentTable[i - dfFirstChar] < dfMinWidth) {
240                 dfMinWidth = extentTable[i - dfFirstChar];
241             }
242         }
243     }
244
245     /**
246      * Returns the Windows name of the font.
247      *
248      * @return The Windows name.
249      */

250     public String JavaDoc getWindowsName() {
251         return windowsName;
252     }
253
254     /**
255      * Return the kerning table. The kerning table is a hashmap with
256      * strings with glyphnames as keys, containing hashmaps as value.
257      * The value hashmaps contain a glyph name string key and an Integer value
258      */

259     public Map JavaDoc getKerning() {
260         return kerningTab;
261     }
262
263     /**
264      * Returns the Postscript name of the font.
265      *
266      * @return The Postscript name.
267      */

268     public String JavaDoc getPostscriptName() {
269         return postscriptName;
270     }
271
272     /**
273      * Returns the charset used for the font.
274      *
275      * @return The charset (0=WinAnsi).
276      */

277     public short getCharSet() {
278         return dfCharSet;
279     }
280
281     /**
282      * Returns the charset of the font as a string.
283      *
284      * @return The name of the charset.
285      */

286     public String JavaDoc getCharSetName() {
287         switch (dfCharSet) {
288         case 0:
289             return "WinAnsi";
290         case 128:
291             return "Shift-JIS (Japanese)";
292         default:
293             return "Unknown";
294         }
295     }
296
297     /**
298      * Returns the number of the character that defines
299      * the first entry in the widths list.
300      *
301      * @return The number of the first character.
302      */

303     public short getFirstChar() {
304         return dfFirstChar;
305     }
306
307     /**
308      * Returns the number of the character that defines
309      * the last entry in the widths list.
310      *
311      * @return The number of the last character.
312      */

313     public short getLastChar() {
314         return dfLastChar;
315     }
316
317     /**
318      * Returns the CapHeight parameter for the font (height of uppercase H).
319      *
320      * @return The CapHeight parameter.
321      */

322     public int getCapHeight() {
323         return etmCapHeight;
324     }
325
326     /**
327      * Returns the XHeight parameter for the font (height of lowercase x).
328      *
329      * @return The CapHeight parameter.
330      */

331     public int getXHeight() {
332         return etmXHeight;
333     }
334
335     /**
336      * Returns the LowerCaseAscent parameter for the font (height of lowercase d).
337      *
338      * @return The LowerCaseAscent parameter.
339      */

340     public int getLowerCaseAscent() {
341         return etmLowerCaseAscent;
342     }
343
344     /**
345      * Returns the LowerCaseDescent parameter for the font (height of lowercase p).
346      *
347      * @return The LowerCaseDescent parameter.
348      */

349     public int getLowerCaseDescent() {
350         return etmLowerCaseDescent;
351     }
352
353     /**
354      * Tells whether the font has proportional character spacing.
355      *
356      * @return ex. true for Times, false for Courier.
357      */

358     public boolean getIsProportional() {
359         return ((dfPitchAndFamily & 1) == 1);
360     }
361
362     /**
363      * Returns the bounding box for the font.
364      * Note: this value is just an approximation,
365      * it does not really exist in the PFM file.
366      *
367      * @return The calculated Font BBox.
368      */

369     public int[] getFontBBox() {
370         int[] bbox = new int[4];
371
372         // Just guessing....
373
if (!getIsProportional() && (dfAvgWidth == dfMaxWidth)) {
374             bbox[0] = -20;
375         } else {
376             bbox[0] = -100;
377         }
378         bbox[1] = -(getLowerCaseDescent() + 5);
379         bbox[2] = dfMaxWidth + 10;
380         bbox[3] = getLowerCaseAscent() + 5;
381         return bbox;
382     }
383
384     /**
385      * Returns the characteristics flags for the font as
386      * needed for a PDF font descriptor (See PDF specs).
387      *
388      * @return The characteristics flags.
389      */

390     public int getFlags() {
391         int flags = 0;
392         if (!getIsProportional()) {
393             flags |= 1;
394         }
395         if ((dfPitchAndFamily & 16) == 16) {
396             flags |= 2;
397         }
398         if ((dfPitchAndFamily & 64) == 64) {
399             flags |= 4;
400         }
401         if (dfCharSet == 0) {
402             flags |= 6;
403         }
404         if (dfItalic != 0) {
405             flags |= 7;
406         }
407         return flags;
408     }
409
410     /**
411      * Returns the width of the dominant vertical stems of the font.
412      * Note: this value is just an approximation,
413      * it does not really exist in the PFM file.
414      *
415      * @return The vertical stem width.
416      */

417     public int getStemV() {
418         // Just guessing....
419
if (dfItalic != 0) {
420             return (int)Math.round(dfMinWidth * 0.25);
421         } else {
422             return (int)Math.round(dfMinWidth * 0.6);
423         }
424     }
425
426     /**
427      * Returns the italic angle of the font.
428      * Note: this value is just an approximation,
429      * it does not really exist in the PFM file.
430      *
431      * @return The italic angle.
432      */

433     public int getItalicAngle() {
434         if (dfItalic != 0) {
435             return -16; // Just guessing....
436
} else {
437             return 0;
438         }
439     }
440
441     /**
442      * Returns the width of a character
443      *
444      * @param which The number of the character for which the width is requested.
445      * @return The width of a character.
446      */

447     public int getCharWidth(short which) {
448         return extentTable[which - dfFirstChar];
449     }
450
451 }
452
Popular Tags