You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PFMReader.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.fonts.apps;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.util.Iterator;
  22. import java.util.Map;
  23. import javax.xml.parsers.DocumentBuilderFactory;
  24. import org.w3c.dom.Document;
  25. import org.w3c.dom.Element;
  26. import org.apache.commons.logging.LogFactory;
  27. import org.apache.fop.Version;
  28. import org.apache.fop.fonts.type1.PFMFile;
  29. import org.apache.fop.util.CommandLineLogger;
  30. /**
  31. * A tool which reads PFM files from Adobe Type 1 fonts and creates
  32. * XML font metrics file for use in FOP.
  33. */
  34. public class PFMReader extends AbstractFontReader {
  35. /**
  36. * Main constructor.
  37. */
  38. public PFMReader() {
  39. super();
  40. }
  41. private static void displayUsage() {
  42. System.out.println(
  43. "java " + PFMReader.class.getName() + " [options] metricfile.pfm xmlfile.xml");
  44. System.out.println();
  45. System.out.println("where options can be:");
  46. System.out.println("-d Debug mode");
  47. System.out.println("-q Quiet mode");
  48. System.out.println("-fn <fontname>");
  49. System.out.println(" default is to use the fontname in the .pfm file, but");
  50. System.out.println(" you can override that name to make sure that the");
  51. System.out.println(" embedded font is used (if you're embedding fonts)");
  52. System.out.println(" instead of installed fonts when viewing documents ");
  53. System.out.println(" with Acrobat Reader.");
  54. }
  55. /**
  56. * The main method for the PFM reader tool.
  57. *
  58. * @param args Command-line arguments: [options] metricfile.pfm xmlfile.xml
  59. * where options can be:
  60. * -fn <fontname>
  61. * default is to use the fontname in the .pfm file, but you can override
  62. * that name to make sure that the embedded font is used instead of installed
  63. * fonts when viewing documents with Acrobat Reader.
  64. * -cn <classname>
  65. * default is to use the fontname
  66. * -ef <path to the Type1 .pfb fontfile>
  67. * will add the possibility to embed the font. When running fop, fop will look
  68. * for this file to embed it
  69. * -er <path to Type1 fontfile relative to org/apache/fop/render/pdf/fonts>
  70. * you can also include the fontfile in the fop.jar file when building fop.
  71. * You can use both -ef and -er. The file specified in -ef will be searched first,
  72. * then the -er file.
  73. */
  74. public static void main(String[] args) {
  75. String embFile = null;
  76. String embResource = null;
  77. String className = null;
  78. String fontName = null;
  79. Map options = new java.util.HashMap();
  80. String[] arguments = parseArguments(options, args);
  81. // Enable the simple command line logging when no other logger is
  82. // defined.
  83. LogFactory logFactory = LogFactory.getFactory();
  84. if (System.getProperty("org.apache.commons.logging.Log") == null) {
  85. logFactory.setAttribute("org.apache.commons.logging.Log",
  86. CommandLineLogger.class.getName());
  87. }
  88. determineLogLevel(options);
  89. PFMReader app = new PFMReader();
  90. log.info("PFM Reader for Apache FOP " + Version.getVersion() + "\n");
  91. if (options.get("-ef") != null) {
  92. embFile = (String)options.get("-ef");
  93. }
  94. if (options.get("-er") != null) {
  95. embResource = (String)options.get("-er");
  96. }
  97. if (options.get("-fn") != null) {
  98. fontName = (String)options.get("-fn");
  99. }
  100. if (options.get("-cn") != null) {
  101. className = (String)options.get("-cn");
  102. }
  103. if (arguments.length != 2 || options.get("-h") != null
  104. || options.get("-help") != null || options.get("--help") != null) {
  105. displayUsage();
  106. } else {
  107. try {
  108. log.info("Parsing font...");
  109. PFMFile pfm = app.loadPFM(arguments[0]);
  110. if (pfm != null) {
  111. app.preview(pfm);
  112. Document doc = app.constructFontXML(pfm,
  113. fontName, className, embResource, embFile);
  114. app.writeFontXML(doc, arguments[1]);
  115. }
  116. log.info("XML font metrics file successfullly created.");
  117. } catch (Exception e) {
  118. log.error("Error while building XML font metrics file", e);
  119. System.exit(-1);
  120. }
  121. }
  122. }
  123. /**
  124. * Read a PFM file and returns it as an object.
  125. *
  126. * @param filename The filename of the PFM file.
  127. * @return The PFM as an object.
  128. * @throws IOException In case of an I/O problem
  129. */
  130. public PFMFile loadPFM(String filename) throws IOException {
  131. log.info("Reading " + filename + "...");
  132. log.info("");
  133. InputStream in = new java.io.FileInputStream(filename);
  134. try {
  135. PFMFile pfm = new PFMFile();
  136. pfm.load(in);
  137. return pfm;
  138. } finally {
  139. in.close();
  140. }
  141. }
  142. /**
  143. * Displays a preview of the PFM file on the console.
  144. *
  145. * @param pfm The PFM file to preview.
  146. */
  147. public void preview(PFMFile pfm) {
  148. if (log != null && log.isInfoEnabled()) {
  149. log.info("Font: " + pfm.getWindowsName());
  150. log.info("Name: " + pfm.getPostScriptName());
  151. log.info("CharSet: " + pfm.getCharSetName());
  152. log.info("CapHeight: " + pfm.getCapHeight());
  153. log.info("XHeight: " + pfm.getXHeight());
  154. log.info("LowerCaseAscent: " + pfm.getLowerCaseAscent());
  155. log.info("LowerCaseDescent: " + pfm.getLowerCaseDescent());
  156. log.info("Having widths for " + (pfm.getLastChar() - pfm.getFirstChar())
  157. + " characters (" + pfm.getFirstChar()
  158. + "-" + pfm.getLastChar() + ").");
  159. log.info("for example: Char " + pfm.getFirstChar()
  160. + " has a width of " + pfm.getCharWidth(pfm.getFirstChar()));
  161. log.info("");
  162. }
  163. }
  164. /**
  165. * Generates the font metrics file from the PFM file.
  166. *
  167. * @param pfm The PFM file to generate the font metrics from.
  168. * @param fontName name of the font
  169. * @param className class name for the font
  170. * @param resource path to the font as embedded resource
  171. * @param file path to the font as file
  172. * @return The DOM document representing the font metrics file.
  173. */
  174. public org.w3c.dom.Document constructFontXML(PFMFile pfm,
  175. String fontName, String className, String resource, String file) {
  176. log.info("Creating xml font file...");
  177. log.info("");
  178. Document doc;
  179. try {
  180. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  181. doc = factory.newDocumentBuilder().newDocument();
  182. } catch (javax.xml.parsers.ParserConfigurationException e) {
  183. log.error("Can't create DOM implementation", e);
  184. return null;
  185. }
  186. Element root = doc.createElement("font-metrics");
  187. doc.appendChild(root);
  188. root.setAttribute("type", "TYPE1");
  189. Element el = doc.createElement("font-name");
  190. root.appendChild(el);
  191. el.appendChild(doc.createTextNode(pfm.getPostScriptName()));
  192. // Currently unused.
  193. // String s = pfm.getPostscriptName();
  194. // int pos = s.indexOf("-");
  195. // if (pos >= 0) {
  196. // char[] sb = new char[s.length() - 1];
  197. // s.getChars(0, pos, sb, 0);
  198. // s.getChars(pos + 1, s.length(), sb, pos);
  199. // s = new String(sb);
  200. // }
  201. el = doc.createElement("embed");
  202. root.appendChild(el);
  203. if (file != null) {
  204. el.setAttribute("file", file);
  205. }
  206. if (resource != null) {
  207. el.setAttribute("class", resource);
  208. }
  209. el = doc.createElement("encoding");
  210. root.appendChild(el);
  211. el.appendChild(doc.createTextNode(pfm.getCharSetName() + "Encoding"));
  212. el = doc.createElement("cap-height");
  213. root.appendChild(el);
  214. Integer value = new Integer(pfm.getCapHeight());
  215. el.appendChild(doc.createTextNode(value.toString()));
  216. el = doc.createElement("x-height");
  217. root.appendChild(el);
  218. value = new Integer(pfm.getXHeight());
  219. el.appendChild(doc.createTextNode(value.toString()));
  220. el = doc.createElement("ascender");
  221. root.appendChild(el);
  222. value = new Integer(pfm.getLowerCaseAscent());
  223. el.appendChild(doc.createTextNode(value.toString()));
  224. el = doc.createElement("descender");
  225. root.appendChild(el);
  226. value = new Integer(pfm.getLowerCaseDescent());
  227. el.appendChild(doc.createTextNode(value.toString()));
  228. Element bbox = doc.createElement("bbox");
  229. root.appendChild(bbox);
  230. int[] bb = pfm.getFontBBox();
  231. final String[] names = {"left", "bottom", "right", "top"};
  232. for (int i = 0; i < names.length; i++) {
  233. el = doc.createElement(names[i]);
  234. bbox.appendChild(el);
  235. value = new Integer(bb[i]);
  236. el.appendChild(doc.createTextNode(value.toString()));
  237. }
  238. el = doc.createElement("flags");
  239. root.appendChild(el);
  240. value = new Integer(pfm.getFlags());
  241. el.appendChild(doc.createTextNode(value.toString()));
  242. el = doc.createElement("stemv");
  243. root.appendChild(el);
  244. value = new Integer(pfm.getStemV());
  245. el.appendChild(doc.createTextNode(value.toString()));
  246. el = doc.createElement("italicangle");
  247. root.appendChild(el);
  248. value = new Integer(pfm.getItalicAngle());
  249. el.appendChild(doc.createTextNode(value.toString()));
  250. el = doc.createElement("first-char");
  251. root.appendChild(el);
  252. value = new Integer(pfm.getFirstChar());
  253. el.appendChild(doc.createTextNode(value.toString()));
  254. el = doc.createElement("last-char");
  255. root.appendChild(el);
  256. value = new Integer(pfm.getLastChar());
  257. el.appendChild(doc.createTextNode(value.toString()));
  258. Element widths = doc.createElement("widths");
  259. root.appendChild(widths);
  260. for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) {
  261. el = doc.createElement("char");
  262. widths.appendChild(el);
  263. el.setAttribute("idx", Integer.toString(i));
  264. el.setAttribute("wdt", Integer.toString(pfm.getCharWidth(i)));
  265. }
  266. // Get kerning
  267. Iterator iter = pfm.getKerning().keySet().iterator();
  268. while (iter.hasNext()) {
  269. Integer kpx1 = (Integer)iter.next();
  270. el = doc.createElement("kerning");
  271. el.setAttribute("kpx1", kpx1.toString());
  272. root.appendChild(el);
  273. Element el2 = null;
  274. Map h2 = (Map) pfm.getKerning().get(kpx1);
  275. Iterator enum2 = h2.entrySet().iterator();
  276. while (enum2.hasNext()) {
  277. Map.Entry entry = (Map.Entry) enum2.next();
  278. Integer kpx2 = (Integer) entry.getKey();
  279. el2 = doc.createElement("pair");
  280. el2.setAttribute("kpx2", kpx2.toString());
  281. Integer val = (Integer) entry.getValue();
  282. el2.setAttribute("kern", val.toString());
  283. el.appendChild(el2);
  284. }
  285. }
  286. return doc;
  287. }
  288. }