001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: PFMReader.java 426576 2006-07-28 15:44:37Z jeremias $ */
019:
020: package org.apache.fop.fonts.apps;
021:
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.util.Iterator;
025: import java.util.Map;
026:
027: import javax.xml.parsers.DocumentBuilderFactory;
028:
029: import org.apache.commons.logging.LogFactory;
030: import org.apache.fop.Version;
031: import org.apache.fop.fonts.type1.PFMFile;
032: import org.apache.fop.util.CommandLineLogger;
033: import org.w3c.dom.Document;
034: import org.w3c.dom.Element;
035:
036: /**
037: * A tool which reads PFM files from Adobe Type 1 fonts and creates
038: * XML font metrics file for use in FOP.
039: */
040: public class PFMReader extends AbstractFontReader {
041:
042: /**
043: * Main constructor.
044: */
045: public PFMReader() {
046: super ();
047: }
048:
049: private static void displayUsage() {
050: System.out.println("java " + PFMReader.class.getName()
051: + " [options] metricfile.pfm xmlfile.xml");
052: System.out.println();
053: System.out.println("where options can be:");
054: System.out.println("-d Debug mode");
055: System.out.println("-q Quiet mode");
056: System.out.println("-fn <fontname>");
057: System.out
058: .println(" default is to use the fontname in the .pfm file, but");
059: System.out
060: .println(" you can override that name to make sure that the");
061: System.out
062: .println(" embedded font is used (if you're embedding fonts)");
063: System.out
064: .println(" instead of installed fonts when viewing documents ");
065: System.out.println(" with Acrobat Reader.");
066: }
067:
068: /**
069: * The main method for the PFM reader tool.
070: *
071: * @param args Command-line arguments: [options] metricfile.pfm xmlfile.xml
072: * where options can be:
073: * -fn <fontname>
074: * default is to use the fontname in the .pfm file, but you can override
075: * that name to make sure that the embedded font is used instead of installed
076: * fonts when viewing documents with Acrobat Reader.
077: * -cn <classname>
078: * default is to use the fontname
079: * -ef <path to the Type1 .pfb fontfile>
080: * will add the possibility to embed the font. When running fop, fop will look
081: * for this file to embed it
082: * -er <path to Type1 fontfile relative to org/apache/fop/render/pdf/fonts>
083: * you can also include the fontfile in the fop.jar file when building fop.
084: * You can use both -ef and -er. The file specified in -ef will be searched first,
085: * then the -er file.
086: */
087: public static void main(String[] args) {
088: String embFile = null;
089: String embResource = null;
090: String className = null;
091: String fontName = null;
092:
093: Map options = new java.util.HashMap();
094: String[] arguments = parseArguments(options, args);
095:
096: // Enable the simple command line logging when no other logger is
097: // defined.
098: LogFactory logFactory = LogFactory.getFactory();
099: if (System.getProperty("org.apache.commons.logging.Log") == null) {
100: logFactory.setAttribute("org.apache.commons.logging.Log",
101: CommandLineLogger.class.getName());
102: }
103:
104: determineLogLevel(options);
105:
106: PFMReader app = new PFMReader();
107:
108: log.info("PFM Reader for Apache FOP " + Version.getVersion()
109: + "\n");
110:
111: if (options.get("-ef") != null) {
112: embFile = (String) options.get("-ef");
113: }
114:
115: if (options.get("-er") != null) {
116: embResource = (String) options.get("-er");
117: }
118:
119: if (options.get("-fn") != null) {
120: fontName = (String) options.get("-fn");
121: }
122:
123: if (options.get("-cn") != null) {
124: className = (String) options.get("-cn");
125: }
126:
127: if (arguments.length != 2 || options.get("-h") != null
128: || options.get("-help") != null
129: || options.get("--help") != null) {
130: displayUsage();
131: } else {
132: try {
133: log.info("Parsing font...");
134: PFMFile pfm = app.loadPFM(arguments[0]);
135: if (pfm != null) {
136: app.preview(pfm);
137:
138: Document doc = app.constructFontXML(pfm, fontName,
139: className, embResource, embFile);
140:
141: app.writeFontXML(doc, arguments[1]);
142: }
143: log
144: .info("XML font metrics file successfullly created.");
145: } catch (Exception e) {
146: log.error("Error while building XML font metrics file",
147: e);
148: System.exit(-1);
149: }
150: }
151: }
152:
153: /**
154: * Read a PFM file and returns it as an object.
155: *
156: * @param filename The filename of the PFM file.
157: * @return The PFM as an object.
158: * @throws IOException In case of an I/O problem
159: */
160: public PFMFile loadPFM(String filename) throws IOException {
161: log.info("Reading " + filename + "...");
162: log.info("");
163: InputStream in = new java.io.FileInputStream(filename);
164: try {
165: PFMFile pfm = new PFMFile();
166: pfm.load(in);
167: return pfm;
168: } finally {
169: in.close();
170: }
171: }
172:
173: /**
174: * Displays a preview of the PFM file on the console.
175: *
176: * @param pfm The PFM file to preview.
177: */
178: public void preview(PFMFile pfm) {
179: if (log != null & log.isInfoEnabled()) {
180: log.info("Font: " + pfm.getWindowsName());
181: log.info("Name: " + pfm.getPostscriptName());
182: log.info("CharSet: " + pfm.getCharSetName());
183: log.info("CapHeight: " + pfm.getCapHeight());
184: log.info("XHeight: " + pfm.getXHeight());
185: log.info("LowerCaseAscent: " + pfm.getLowerCaseAscent());
186: log.info("LowerCaseDescent: " + pfm.getLowerCaseDescent());
187: log.info("Having widths for "
188: + (pfm.getLastChar() - pfm.getFirstChar())
189: + " characters (" + pfm.getFirstChar() + "-"
190: + pfm.getLastChar() + ").");
191: log.info("for example: Char " + pfm.getFirstChar()
192: + " has a width of "
193: + pfm.getCharWidth(pfm.getFirstChar()));
194: log.info("");
195: }
196: }
197:
198: /**
199: * Generates the font metrics file from the PFM file.
200: *
201: * @param pfm The PFM file to generate the font metrics from.
202: * @param fontName name of the font
203: * @param className class name for the font
204: * @param resource path to the font as embedded resource
205: * @param file path to the font as file
206: * @return The DOM document representing the font metrics file.
207: */
208: public org.w3c.dom.Document constructFontXML(PFMFile pfm,
209: String fontName, String className, String resource,
210: String file) {
211: log.info("Creating xml font file...");
212: log.info("");
213:
214: Document doc;
215: try {
216: DocumentBuilderFactory factory = DocumentBuilderFactory
217: .newInstance();
218: doc = factory.newDocumentBuilder().newDocument();
219: } catch (javax.xml.parsers.ParserConfigurationException e) {
220: log.error("Can't create DOM implementation", e);
221: return null;
222: }
223: Element root = doc.createElement("font-metrics");
224: doc.appendChild(root);
225: root.setAttribute("type", "TYPE1");
226:
227: Element el = doc.createElement("font-name");
228: root.appendChild(el);
229: el.appendChild(doc.createTextNode(pfm.getPostscriptName()));
230:
231: String s = pfm.getPostscriptName();
232: int pos = s.indexOf("-");
233: if (pos >= 0) {
234: char[] sb = new char[s.length() - 1];
235: s.getChars(0, pos, sb, 0);
236: s.getChars(pos + 1, s.length(), sb, pos);
237: s = new String(sb);
238: }
239:
240: el = doc.createElement("embed");
241: root.appendChild(el);
242: if (file != null) {
243: el.setAttribute("file", file);
244: }
245: if (resource != null) {
246: el.setAttribute("class", resource);
247: }
248:
249: el = doc.createElement("encoding");
250: root.appendChild(el);
251: el.appendChild(doc.createTextNode(pfm.getCharSetName()
252: + "Encoding"));
253:
254: el = doc.createElement("cap-height");
255: root.appendChild(el);
256: Integer value = new Integer(pfm.getCapHeight());
257: el.appendChild(doc.createTextNode(value.toString()));
258:
259: el = doc.createElement("x-height");
260: root.appendChild(el);
261: value = new Integer(pfm.getXHeight());
262: el.appendChild(doc.createTextNode(value.toString()));
263:
264: el = doc.createElement("ascender");
265: root.appendChild(el);
266: value = new Integer(pfm.getLowerCaseAscent());
267: el.appendChild(doc.createTextNode(value.toString()));
268:
269: el = doc.createElement("descender");
270: root.appendChild(el);
271: value = new Integer(-pfm.getLowerCaseDescent());
272: el.appendChild(doc.createTextNode(value.toString()));
273:
274: Element bbox = doc.createElement("bbox");
275: root.appendChild(bbox);
276: int[] bb = pfm.getFontBBox();
277: final String[] names = { "left", "bottom", "right", "top" };
278: for (int i = 0; i < names.length; i++) {
279: el = doc.createElement(names[i]);
280: bbox.appendChild(el);
281: value = new Integer(bb[i]);
282: el.appendChild(doc.createTextNode(value.toString()));
283: }
284:
285: el = doc.createElement("flags");
286: root.appendChild(el);
287: value = new Integer(pfm.getFlags());
288: el.appendChild(doc.createTextNode(value.toString()));
289:
290: el = doc.createElement("stemv");
291: root.appendChild(el);
292: value = new Integer(pfm.getStemV());
293: el.appendChild(doc.createTextNode(value.toString()));
294:
295: el = doc.createElement("italicangle");
296: root.appendChild(el);
297: value = new Integer(pfm.getItalicAngle());
298: el.appendChild(doc.createTextNode(value.toString()));
299:
300: el = doc.createElement("first-char");
301: root.appendChild(el);
302: value = new Integer(pfm.getFirstChar());
303: el.appendChild(doc.createTextNode(value.toString()));
304:
305: el = doc.createElement("last-char");
306: root.appendChild(el);
307: value = new Integer(pfm.getLastChar());
308: el.appendChild(doc.createTextNode(value.toString()));
309:
310: Element widths = doc.createElement("widths");
311: root.appendChild(widths);
312:
313: for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) {
314: el = doc.createElement("char");
315: widths.appendChild(el);
316: el.setAttribute("idx", Integer.toString(i));
317: el.setAttribute("wdt", new Integer(pfm.getCharWidth(i))
318: .toString());
319: }
320:
321: // Get kerning
322: Iterator iter = pfm.getKerning().keySet().iterator();
323: while (iter.hasNext()) {
324: Integer kpx1 = (Integer) iter.next();
325: el = doc.createElement("kerning");
326: el.setAttribute("kpx1", kpx1.toString());
327: root.appendChild(el);
328: Element el2 = null;
329:
330: Map h2 = (Map) pfm.getKerning().get(kpx1);
331: Iterator enum2 = h2.keySet().iterator();
332: while (enum2.hasNext()) {
333: Integer kpx2 = (Integer) enum2.next();
334: el2 = doc.createElement("pair");
335: el2.setAttribute("kpx2", kpx2.toString());
336: Integer val = (Integer) h2.get(kpx2);
337: el2.setAttribute("kern", val.toString());
338: el.appendChild(el2);
339: }
340: }
341: return doc;
342: }
343: }
|