KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fonts > apps > TTFReader


1 /*
2  * $Id: TTFReader.java,v 1.4.2.4 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.apps;
52
53 import java.io.*;
54 import org.w3c.dom.*;
55 import org.apache.fop.fonts.*;
56 import java.util.HashMap;
57 import java.util.ArrayList;
58 import java.util.Iterator;
59
60 /**
61  * A tool which reads TTF files and generates
62  * XML font metrics file for use in FOP.
63  *
64  */

65 public class TTFReader {
66
67     private boolean invokedStandalone = false;
68
69     public TTFReader() {}
70
71
72     /**
73      * Parse commandline arguments. put options in the HashMap and return
74      * arguments in the String array
75      * the arguments: -fn Perpetua,Bold -cn PerpetuaBold per.ttf Perpetua.xml
76      * returns a String[] with the per.ttf and Perpetua.xml. The hash
77      * will have the (key, value) pairs: (-fn, Perpetua) and (-cn, PerpetuaBold)
78      */

79     private static String[] parseArguments(HashMap options, String[] args) {
80         ArrayList arguments = new ArrayList();
81         for (int i = 0; i < args.length; i++) {
82             if (args[i].startsWith("-")) {
83                 if ((i + 1) < args.length &&!args[i + 1].startsWith("-")) {
84                     options.put(args[i], args[i + 1]);
85                     i++;
86                 } else {
87                     options.put(args[i], "");
88                 }
89             } else {
90                 arguments.add(args[i]);
91             }
92         }
93
94         String[] argStrings = new String[arguments.size()];
95         arguments.toArray(argStrings);
96         return argStrings;
97     }
98
99
100     private static final void displayUsage() {
101         System.out.println(" java org.apache.fop.fonts.apps.TTFReader [options] fontfile.ttf xmlfile.xml\n");
102         System.out.println(" where options can be:\n");
103         System.out.println("-enc ansi");
104         System.out.println(" With this option you create a WinAnsi encoded font.\n");
105         System.out.println(" The default is to create a CID keyed font.");
106         System.out.println(" If you're not going to use characters outside the");
107         System.out.println(" pdfencoding range (almost the same as iso-8889-1)");
108         System.out.println(" you can add this option.");
109         System.out.println("-ttcname <fontname>");
110         System.out.println(" If you're reading data from a TrueType Collection");
111         System.out.println(" (.ttc file) you must specify which font from the");
112         System.out.println(" collection you will read metrics from. If you read");
113         System.out.println(" from a .ttc file without this option, the fontnames");
114         System.out.println(" will be listed for you.");
115         System.out.println(" -fn <fontname>\n");
116         System.out.println(" default is to use the fontname in the .ttf file, but\n"
117                            + " you can override that name to make sure that the\n");
118         System.out.println(" embedded font is used (if you're embedding fonts)\n");
119         System.out.println(" instead of installed fonts when viewing documents with Acrobat Reader.\n");
120     }
121
122
123     /**
124      * The main method for the TTFReader tool.
125      *
126      * @param args Command-line arguments: [options] fontfile.ttf xmlfile.xml
127      * where options can be:
128      * -fn <fontname>
129      * default is to use the fontname in the .ttf file, but you can override
130      * that name to make sure that the embedded font is used instead of installed
131      * fonts when viewing documents with Acrobat Reader.
132      * -cn <classname>
133      * default is to use the fontname
134      * -ef <path to the truetype fontfile>
135      * will add the possibility to embed the font. When running fop, fop will look
136      * for this file to embed it
137      * -er <path to truetype fontfile relative to org/apache/fop/render/pdf/fonts>
138      * you can also include the fontfile in the fop.jar file when building fop.
139      * You can use both -ef and -er. The file specified in -ef will be searched first,
140      * then the -er file.
141      */

142     public static void main(String[] args) {
143         String embFile = null;
144         String embResource = null;
145         String className = null;
146         String fontName = null;
147         String ttcName = null;
148         boolean isCid = true;
149
150         HashMap options = new HashMap();
151         String[] arguments = parseArguments(options, args);
152
153         TTFReader app = new TTFReader();
154         app.invokedStandalone = true;
155
156         System.out.println("TTF Reader v1.1.1");
157         System.out.println();
158
159         if (options.get("-enc") != null) {
160             String enc = (String)options.get("-enc");
161             if ("ansi".equals(enc))
162                 isCid = false;
163         }
164
165         if (options.get("-ttcname") != null)
166             ttcName = (String)options.get("-ttcname");
167
168         if (options.get("-ef") != null)
169             embFile = (String)options.get("-ef");
170
171         if (options.get("-er") != null)
172             embResource = (String)options.get("-er");
173
174         if (options.get("-fn") != null)
175             fontName = (String)options.get("-fn");
176
177         if (options.get("-cn") != null)
178             className = (String)options.get("-cn");
179
180         if (arguments.length != 2 || options.get("-h") != null
181             || options.get("-help") != null || options.get("--help") != null)
182             displayUsage();
183         else {
184             TTFFile ttf = app.loadTTF(arguments[0], ttcName);
185             if (ttf != null) {
186                 org.w3c.dom.Document doc = app.constructFontXML(ttf,
187                         fontName, className, embResource, embFile, isCid,
188                         ttcName);
189
190                 if (isCid)
191                     System.out.println("Creating CID encoded metrics");
192                 else
193                     System.out.println("Creating WinAnsi encoded metrics");
194
195                 if (doc != null) {
196                     app.writeFontXML(doc, arguments[1]);
197                 }
198
199                 if (ttf.isEmbeddable())
200                     System.out.println("This font contains no embedding license restrictions");
201                 else
202                     System.out.println("** Note: This font contains license retrictions for\n"
203                                        + " embedding. This font shouldn't be embedded.");
204
205             }
206         }
207     }
208
209     /**
210      * Read a TTF file and returns it as an object.
211      *
212      * @param filename The filename of the PFM file.
213      * @return The TTF as an object.
214      */

215     public TTFFile loadTTF(String fileName, String fontName) {
216         TTFFile ttfFile = new TTFFile();
217         try {
218             System.out.println("Reading " + fileName + "...");
219             System.out.println();
220
221             FontFileReader reader = new FontFileReader(fileName);
222             ttfFile.readFont(reader, fontName);
223         } catch (Exception e) {
224             e.printStackTrace();
225             return null;
226         }
227         return ttfFile;
228     }
229
230
231     /**
232      * Writes the generated DOM Document to a file.
233      *
234      * @param doc The DOM Document to save.
235      * @param target The target filename for the XML file.
236      */

237     public void writeFontXML(org.w3c.dom.Document doc, String target) {
238         System.out.println("Writing xml font file " + target + "...");
239         System.out.println();
240
241         try {
242           javax.xml.transform.TransformerFactory.newInstance()
243             .newTransformer().transform(
244               new javax.xml.transform.dom.DOMSource(doc),
245               new javax.xml.transform.stream.StreamResult(new File(target)));
246
247 /* OutputFormat format = new OutputFormat(doc); // Serialize DOM
248             FileWriter out = new FileWriter(target); // Writer will be a String
249             XMLSerializer serial = new XMLSerializer(out, format);
250             serial.asDOMSerializer(); // As a DOM Serializer
251
252             serial.serialize(doc.getDocumentElement());
253             out.close();
254 */

255         } catch (Exception e) {
256             e.printStackTrace();
257         }
258     }
259
260     /**
261      * Generates the font metrics file from the TTF/TTC file.
262      *
263      * @param ttf The PFM file to generate the font metrics from.
264      * @return The DOM document representing the font metrics file.
265      */

266     public org.w3c.dom.Document constructFontXML(TTFFile ttf,
267             String fontName, String className, String resource, String file,
268             boolean isCid, String ttcName) {
269         System.out.println("Creating xml font file...");
270         System.out.println();
271
272 // Document doc = new DocumentImpl();
273
Document doc;
274         try {
275           doc = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
276         }
277         catch (javax.xml.parsers.ParserConfigurationException e) {
278           System.out.println("Can't create DOM implementation "+e.getMessage());
279           return null;
280         }
281         Element root = doc.createElement("font-metrics");
282         doc.appendChild(root);
283         if (isCid)
284             root.setAttribute("type", "TYPE0");
285         else
286             root.setAttribute("type", "TRUETYPE");
287
288         Element el = doc.createElement("font-name");
289         root.appendChild(el);
290
291         // Note that the PostScript name usually is something like
292
// "Perpetua-Bold", but the TrueType spec says that in the ttf file
293
// it should be "Perpetua,Bold".
294

295         String s = stripWhiteSpace(ttf.getPostscriptName());
296
297         if (fontName != null)
298             el.appendChild(doc.createTextNode(stripWhiteSpace(fontName)));
299         else
300             el.appendChild(doc.createTextNode(s));
301
302         el = doc.createElement("embed");
303         root.appendChild(el);
304         if (file != null && ttf.isEmbeddable())
305             el.setAttribute("file", file);
306         if (resource != null && ttf.isEmbeddable())
307             el.setAttribute("class", resource);
308
309         el = doc.createElement("cap-height");
310         root.appendChild(el);
311         el.appendChild(doc.createTextNode(String.valueOf(ttf.getCapHeight())));
312
313         el = doc.createElement("x-height");
314         root.appendChild(el);
315         el.appendChild(doc.createTextNode(String.valueOf(ttf.getXHeight())));
316
317         el = doc.createElement("ascender");
318         root.appendChild(el);
319         el.appendChild(doc.createTextNode(String.valueOf(ttf.getLowerCaseAscent())));
320
321         el = doc.createElement("descender");
322         root.appendChild(el);
323         el.appendChild(doc.createTextNode(String.valueOf(ttf.getLowerCaseDescent())));
324
325         Element bbox = doc.createElement("bbox");
326         root.appendChild(bbox);
327         int[] bb = ttf.getFontBBox();
328         String[] names = {
329             "left", "bottom", "right", "top"
330         };
331         for (int i = 0; i < 4; i++) {
332             el = doc.createElement(names[i]);
333             bbox.appendChild(el);
334             el.appendChild(doc.createTextNode(String.valueOf(bb[i])));
335         }
336
337         el = doc.createElement("flags");
338         root.appendChild(el);
339         el.appendChild(doc.createTextNode(String.valueOf(ttf.getFlags())));
340
341         el = doc.createElement("stemv");
342         root.appendChild(el);
343         el.appendChild(doc.createTextNode(ttf.getStemV()));
344
345         el = doc.createElement("italicangle");
346         root.appendChild(el);
347         el.appendChild(doc.createTextNode(ttf.getItalicAngle()));
348
349         if (ttcName != null) {
350             el = doc.createElement("ttc-name");
351             root.appendChild(el);
352             el.appendChild(doc.createTextNode(ttcName));
353         }
354
355         el = doc.createElement("subtype");
356         root.appendChild(el);
357
358         // Fill in extras for CID keyed fonts
359
if (isCid) {
360             el.appendChild(doc.createTextNode("TYPE0"));
361
362             Element mel = doc.createElement("multibyte-extras");
363             root.appendChild(mel);
364
365             el = doc.createElement("cid-type");
366             mel.appendChild(el);
367             el.appendChild(doc.createTextNode("CIDFontType2"));
368
369             el = doc.createElement("default-width");
370             mel.appendChild(el);
371             el.appendChild(doc.createTextNode("0"));
372
373             el = doc.createElement("bfranges");
374             mel.appendChild(el);
375             ArrayList cmaps = ttf.getCMaps();
376             for (int i = 0;i < cmaps.size(); i++) {
377                 TTFCmapEntry ce = (TTFCmapEntry)cmaps.get(i);
378                 Element el2 = doc.createElement("bf");
379                 el.appendChild(el2);
380                 el2.setAttribute("us", String.valueOf(ce.unicodeStart));
381                 el2.setAttribute("ue", String.valueOf(ce.unicodeEnd));
382                 el2.setAttribute("gi", String.valueOf(ce.glyphStartIndex));
383             }
384
385             el = doc.createElement("cid-widths");
386             el.setAttribute("start-index", "0");
387             mel.appendChild(el);
388
389             int[] wx = ttf.getWidths();
390             for (int i = 0; i < wx.length; i++) {
391                 Element wxel = doc.createElement("wx");
392                 wxel.setAttribute("w", String.valueOf(wx[i]));
393                 el.appendChild(wxel);
394             }
395         } else {
396             // Fill in extras for singlebyte fonts
397
el.appendChild(doc.createTextNode("TRUETYPE"));
398
399             Element sel = doc.createElement("singlebyte-extras");
400             root.appendChild(sel);
401
402             el = doc.createElement("encoding");
403             sel.appendChild(el);
404             el.appendChild(doc.createTextNode(ttf.getCharSetName()));
405
406             el = doc.createElement("first-char");
407             sel.appendChild(el);
408             el.appendChild(doc.createTextNode(String.valueOf(ttf.getFirstChar())));
409
410             el = doc.createElement("last-char");
411             sel.appendChild(el);
412             el.appendChild(doc.createTextNode(String.valueOf(ttf.getLastChar())));
413
414             Element widths = doc.createElement("widths");
415             sel.appendChild(widths);
416
417             for (short i = ttf.getFirstChar(); i <= ttf.getLastChar(); i++) {
418                 el = doc.createElement("char");
419                 widths.appendChild(el);
420                 el.setAttribute("idx", String.valueOf(i));
421                 el.setAttribute("wdt", String.valueOf(ttf.getCharWidth(i)));
422             }
423         }
424
425         // Get kerning
426
Iterator enum;
427         if (isCid)
428             enum = ttf.getKerning().keySet().iterator();
429         else
430             enum = ttf.getAnsiKerning().keySet().iterator();
431
432         while (enum.hasNext()) {
433             Integer kpx1 = (Integer)enum.next();
434
435             el = doc.createElement("kerning");
436             el.setAttribute("kpx1", kpx1.toString());
437             root.appendChild(el);
438             Element el2 = null;
439
440             HashMap h2;
441             if (isCid)
442                 h2 = (HashMap)ttf.getKerning().get(kpx1);
443             else
444                 h2 = (HashMap)ttf.getAnsiKerning().get(kpx1);
445
446             for (Iterator enum2 = h2.keySet().iterator(); enum2.hasNext(); ) {
447                 Integer kpx2 = (Integer)enum2.next();
448                 if (isCid || kpx2.intValue() < 256) {
449                     el2 = doc.createElement("pair");
450                     el2.setAttribute("kpx2", kpx2.toString());
451                     Integer val = (Integer)h2.get(kpx2);
452                     el2.setAttribute("kern", val.toString());
453                     el.appendChild(el2);
454                 }
455             }
456         }
457
458         return doc;
459     }
460
461
462     private String stripWhiteSpace(String s) {
463         char[] ch = new char[s.length()];
464         s.getChars(0, s.length(), ch, 0);
465         StringBuffer stb = new StringBuffer();
466         for (int i = 0; i < ch.length; i++)
467             if (ch[i] != ' ' && ch[i] != '\r' && ch[i] != '\n'
468                     && ch[i] != '\t')
469                 stb.append(ch[i]);
470
471         return stb.toString();
472     }
473
474     private String escapeString(String str) {
475         StringBuffer esc = new StringBuffer();
476
477         for (int i = 0; i < str.length(); i++) {
478             if (str.charAt(i) == '\\')
479                 esc.append("\\\\");
480             else
481                 esc.append(str.charAt(i));
482         }
483
484         return esc.toString();
485     }
486
487 }
488
489
Popular Tags