blob: e5e8ca524d35eabfea79a016ee6b5e209271a4ca [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.fonts.apps;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.Version;
import org.apache.fop.fonts.type1.PFMFile;
import org.apache.fop.util.CommandLineLogger;
/**
* A tool which reads PFM files from Adobe Type 1 fonts and creates
* XML font metrics file for use in FOP.
*/
public class PFMReader extends AbstractFontReader {
/**
* Main constructor.
*/
public PFMReader() {
super();
}
private static void displayUsage() {
System.out.println(
"java " + PFMReader.class.getName() + " [options] metricfile.pfm xmlfile.xml");
System.out.println();
System.out.println("where options can be:");
System.out.println("-d Debug mode");
System.out.println("-q Quiet mode");
System.out.println("-fn <fontname>");
System.out.println(" default is to use the fontname in the .pfm file, but");
System.out.println(" you can override that name to make sure that the");
System.out.println(" embedded font is used (if you're embedding fonts)");
System.out.println(" instead of installed fonts when viewing documents ");
System.out.println(" with Acrobat Reader.");
}
/**
* The main method for the PFM reader tool.
*
* @param args Command-line arguments: [options] metricfile.pfm xmlfile.xml
* where options can be:
* -fn <fontname>
* default is to use the fontname in the .pfm file, but you can override
* that name to make sure that the embedded font is used instead of installed
* fonts when viewing documents with Acrobat Reader.
* -cn <classname>
* default is to use the fontname
* -ef <path to the Type1 .pfb fontfile>
* will add the possibility to embed the font. When running fop, fop will look
* for this file to embed it
* -er <path to Type1 fontfile relative to org/apache/fop/render/pdf/fonts>
* you can also include the fontfile in the fop.jar file when building fop.
* You can use both -ef and -er. The file specified in -ef will be searched first,
* then the -er file.
*/
public static void main(String[] args) {
String embFile = null;
String embResource = null;
String className = null;
String fontName = null;
Map options = new java.util.HashMap();
String[] arguments = parseArguments(options, args);
// Enable the simple command line logging when no other logger is
// defined.
LogFactory logFactory = LogFactory.getFactory();
if (System.getProperty("org.apache.commons.logging.Log") == null) {
logFactory.setAttribute("org.apache.commons.logging.Log",
CommandLineLogger.class.getName());
}
determineLogLevel(options);
PFMReader app = new PFMReader();
log.info("PFM Reader for Apache FOP " + Version.getVersion() + "\n");
if (options.get("-ef") != null) {
embFile = (String)options.get("-ef");
}
if (options.get("-er") != null) {
embResource = (String)options.get("-er");
}
if (options.get("-fn") != null) {
fontName = (String)options.get("-fn");
}
if (options.get("-cn") != null) {
className = (String)options.get("-cn");
}
if (arguments.length != 2 || options.get("-h") != null
|| options.get("-help") != null || options.get("--help") != null) {
displayUsage();
} else {
try {
log.info("Parsing font...");
PFMFile pfm = app.loadPFM(arguments[0]);
if (pfm != null) {
app.preview(pfm);
Document doc = app.constructFontXML(pfm,
fontName, className, embResource, embFile);
app.writeFontXML(doc, arguments[1]);
}
log.info("XML font metrics file successfullly created.");
} catch (Exception e) {
log.error("Error while building XML font metrics file", e);
System.exit(-1);
}
}
}
/**
* Read a PFM file and returns it as an object.
*
* @param filename The filename of the PFM file.
* @return The PFM as an object.
* @throws IOException In case of an I/O problem
*/
public PFMFile loadPFM(String filename) throws IOException {
log.info("Reading " + filename + "...");
log.info("");
InputStream in = new java.io.FileInputStream(filename);
try {
PFMFile pfm = new PFMFile();
pfm.load(in);
return pfm;
} finally {
in.close();
}
}
/**
* Displays a preview of the PFM file on the console.
*
* @param pfm The PFM file to preview.
*/
public void preview(PFMFile pfm) {
if (log != null && log.isInfoEnabled()) {
log.info("Font: " + pfm.getWindowsName());
log.info("Name: " + pfm.getPostscriptName());
log.info("CharSet: " + pfm.getCharSetName());
log.info("CapHeight: " + pfm.getCapHeight());
log.info("XHeight: " + pfm.getXHeight());
log.info("LowerCaseAscent: " + pfm.getLowerCaseAscent());
log.info("LowerCaseDescent: " + pfm.getLowerCaseDescent());
log.info("Having widths for " + (pfm.getLastChar() - pfm.getFirstChar())
+ " characters (" + pfm.getFirstChar()
+ "-" + pfm.getLastChar() + ").");
log.info("for example: Char " + pfm.getFirstChar()
+ " has a width of " + pfm.getCharWidth(pfm.getFirstChar()));
log.info("");
}
}
/**
* Generates the font metrics file from the PFM file.
*
* @param pfm The PFM file to generate the font metrics from.
* @param fontName name of the font
* @param className class name for the font
* @param resource path to the font as embedded resource
* @param file path to the font as file
* @return The DOM document representing the font metrics file.
*/
public org.w3c.dom.Document constructFontXML(PFMFile pfm,
String fontName, String className, String resource, String file) {
log.info("Creating xml font file...");
log.info("");
Document doc;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
doc = factory.newDocumentBuilder().newDocument();
} catch (javax.xml.parsers.ParserConfigurationException e) {
log.error("Can't create DOM implementation", e);
return null;
}
Element root = doc.createElement("font-metrics");
doc.appendChild(root);
root.setAttribute("type", "TYPE1");
Element el = doc.createElement("font-name");
root.appendChild(el);
el.appendChild(doc.createTextNode(pfm.getPostscriptName()));
// Currently unused.
// String s = pfm.getPostscriptName();
// int pos = s.indexOf("-");
// if (pos >= 0) {
// char[] sb = new char[s.length() - 1];
// s.getChars(0, pos, sb, 0);
// s.getChars(pos + 1, s.length(), sb, pos);
// s = new String(sb);
// }
el = doc.createElement("embed");
root.appendChild(el);
if (file != null) {
el.setAttribute("file", file);
}
if (resource != null) {
el.setAttribute("class", resource);
}
el = doc.createElement("encoding");
root.appendChild(el);
el.appendChild(doc.createTextNode(pfm.getCharSetName() + "Encoding"));
el = doc.createElement("cap-height");
root.appendChild(el);
Integer value = new Integer(pfm.getCapHeight());
el.appendChild(doc.createTextNode(value.toString()));
el = doc.createElement("x-height");
root.appendChild(el);
value = new Integer(pfm.getXHeight());
el.appendChild(doc.createTextNode(value.toString()));
el = doc.createElement("ascender");
root.appendChild(el);
value = new Integer(pfm.getLowerCaseAscent());
el.appendChild(doc.createTextNode(value.toString()));
el = doc.createElement("descender");
root.appendChild(el);
value = new Integer(pfm.getLowerCaseDescent());
el.appendChild(doc.createTextNode(value.toString()));
Element bbox = doc.createElement("bbox");
root.appendChild(bbox);
int[] bb = pfm.getFontBBox();
final String[] names = {"left", "bottom", "right", "top"};
for (int i = 0; i < names.length; i++) {
el = doc.createElement(names[i]);
bbox.appendChild(el);
value = new Integer(bb[i]);
el.appendChild(doc.createTextNode(value.toString()));
}
el = doc.createElement("flags");
root.appendChild(el);
value = new Integer(pfm.getFlags());
el.appendChild(doc.createTextNode(value.toString()));
el = doc.createElement("stemv");
root.appendChild(el);
value = new Integer(pfm.getStemV());
el.appendChild(doc.createTextNode(value.toString()));
el = doc.createElement("italicangle");
root.appendChild(el);
value = new Integer(pfm.getItalicAngle());
el.appendChild(doc.createTextNode(value.toString()));
el = doc.createElement("first-char");
root.appendChild(el);
value = new Integer(pfm.getFirstChar());
el.appendChild(doc.createTextNode(value.toString()));
el = doc.createElement("last-char");
root.appendChild(el);
value = new Integer(pfm.getLastChar());
el.appendChild(doc.createTextNode(value.toString()));
Element widths = doc.createElement("widths");
root.appendChild(widths);
for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) {
el = doc.createElement("char");
widths.appendChild(el);
el.setAttribute("idx", Integer.toString(i));
el.setAttribute("wdt", Integer.toString(pfm.getCharWidth(i)));
}
// Get kerning
Iterator iter = pfm.getKerning().keySet().iterator();
while (iter.hasNext()) {
Integer kpx1 = (Integer)iter.next();
el = doc.createElement("kerning");
el.setAttribute("kpx1", kpx1.toString());
root.appendChild(el);
Element el2 = null;
Map h2 = (Map) pfm.getKerning().get(kpx1);
Iterator enum2 = h2.entrySet().iterator();
while (enum2.hasNext()) {
Map.Entry entry = (Map.Entry) enum2.next();
Integer kpx2 = (Integer) entry.getKey();
el2 = doc.createElement("pair");
el2.setAttribute("kpx2", kpx2.toString());
Integer val = (Integer) entry.getValue();
el2.setAttribute("kern", val.toString());
el.appendChild(el2);
}
}
return doc;
}
}