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.

FontReader.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * $Id$
  3. * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  4. * For details on use and redistribution please refer to the
  5. * LICENSE file included with these sources.
  6. */
  7. package org.apache.fop.render.pdf;
  8. import org.apache.fop.render.pdf.fonts.*;
  9. import org.xml.sax.helpers.DefaultHandler;
  10. import org.xml.sax.XMLReader;
  11. import org.xml.sax.SAXException;
  12. import org.xml.sax.InputSource;
  13. import org.xml.sax.Locator;
  14. import org.xml.sax.Attributes;
  15. import java.io.IOException;
  16. import java.util.Enumeration;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import org.apache.fop.pdf.PDFWArray;
  20. import org.apache.fop.pdf.PDFCIDFont;
  21. import org.apache.fop.apps.FOPException;
  22. /**
  23. * Class for reading a metric.xml file and creating a font object.
  24. * Typical usage:
  25. * <pre>
  26. * FontReader reader = new FontReader(<path til metrics.xml>);
  27. * reader.setFontEmbedPath(<path to a .ttf or .pfb file or null to diable embedding>);
  28. * reader.useKerning(true);
  29. * Font f = reader.getFont();
  30. * </pre>
  31. */
  32. public class FontReader extends DefaultHandler {
  33. private Locator locator = null;
  34. private boolean isCID = false;
  35. private MultiByteFont multiFont = null;
  36. private SingleByteFont singleFont = null;
  37. private Font returnFont = null;
  38. private String text = null;
  39. private ArrayList cidWidths = null;
  40. private int cidWidthIndex = 0;
  41. private HashMap currentKerning = null;
  42. private ArrayList bfranges = null;
  43. private void createFont(String path) throws FOPException {
  44. XMLReader parser = null;
  45. try {
  46. parser = javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser().getXMLReader();
  47. } catch (Exception e) {
  48. throw new FOPException(e);
  49. }
  50. if (parser == null)
  51. throw new FOPException("Unable to create SAX parser");
  52. try {
  53. parser.setFeature("http://xml.org/sax/features/namespace-prefixes",
  54. false);
  55. } catch (SAXException e) {
  56. throw new FOPException("You need a SAX parser which supports SAX version 2",
  57. e);
  58. }
  59. parser.setContentHandler(this);
  60. try {
  61. parser.parse(path);
  62. } catch (SAXException e) {
  63. throw new FOPException(e);
  64. } catch (IOException e) {
  65. throw new FOPException(e);
  66. }
  67. }
  68. /**
  69. * Sets the path to embed a font. a null value disables font embedding
  70. */
  71. public void setFontEmbedPath(String path) {
  72. if (isCID)
  73. multiFont.embedFileName = path;
  74. else
  75. singleFont.embedFileName = path;
  76. }
  77. /**
  78. * Enable/disable use of kerning for the font
  79. */
  80. public void useKerning(boolean kern) {
  81. if (isCID)
  82. multiFont.useKerning = true;
  83. else
  84. singleFont.useKerning = true;
  85. }
  86. /**
  87. * Get the generated font object
  88. */
  89. public Font getFont() {
  90. return returnFont;
  91. }
  92. /**
  93. * Construct a FontReader object from a path to a metric.xml file
  94. * and read metric data
  95. */
  96. public FontReader(String path) throws FOPException {
  97. createFont(path);
  98. }
  99. public void startDocument() {}
  100. public void setDocumentLocator(Locator locator) {
  101. this.locator = locator;
  102. }
  103. public void startElement(String uri, String localName, String qName,
  104. Attributes attributes) {
  105. if (localName.equals("font-metrics")) {
  106. if ("TYPE0".equals(attributes.getValue("type"))) {
  107. multiFont = new MultiByteFont();
  108. returnFont = multiFont;
  109. isCID = true;
  110. } else if ("TRUETYPE".equals(attributes.getValue("type"))) {
  111. singleFont = new SingleByteFont();
  112. singleFont.subType = org.apache.fop.pdf.PDFFont.TRUETYPE;
  113. returnFont = singleFont;
  114. isCID = false;
  115. } else {
  116. singleFont = new SingleByteFont();
  117. singleFont.subType = org.apache.fop.pdf.PDFFont.TYPE1;
  118. returnFont = singleFont;
  119. isCID = false;
  120. }
  121. } else if ("embed".equals(localName)) {
  122. if (isCID) {
  123. // This *is* annoying... should create a common
  124. // interface for sing/multibytefonts...
  125. multiFont.embedFileName = attributes.getValue("file");
  126. multiFont.embedResourceName = attributes.getValue("class");
  127. } else {
  128. singleFont.embedFileName = attributes.getValue("file");
  129. singleFont.embedResourceName = attributes.getValue("class");
  130. }
  131. } else if ("cid-widths".equals(localName)) {
  132. cidWidthIndex = getInt(attributes.getValue("start-index"));
  133. cidWidths = new ArrayList();
  134. } else if ("kerning".equals(localName)) {
  135. currentKerning = new HashMap();
  136. if (isCID)
  137. multiFont.kerning.put(new Integer(attributes.getValue("kpx1")),
  138. currentKerning);
  139. else
  140. singleFont.kerning.put(new Integer(attributes.getValue("kpx1")),
  141. currentKerning);
  142. } else if ("bfranges".equals(localName)) {
  143. bfranges = new ArrayList();
  144. } else if ("bf".equals(localName)) {
  145. BFEntry entry = new BFEntry();
  146. entry.unicodeStart = getInt(attributes.getValue("us"));
  147. entry.unicodeEnd = getInt(attributes.getValue("ue"));
  148. entry.glyphStartIndex = getInt(attributes.getValue("gi"));
  149. bfranges.add(entry);
  150. } else if ("wx".equals(localName)) {
  151. cidWidths.add(new Integer(attributes.getValue("w")));
  152. } else if ("widths".equals(localName)) {
  153. singleFont.width = new int[256];
  154. } else if ("char".equals(localName)) {
  155. try {
  156. singleFont.width[Integer.parseInt(attributes.getValue("idx"))] =
  157. Integer.parseInt(attributes.getValue("wdt"));
  158. } catch (NumberFormatException ne) {
  159. System.out.println("Malformed width in metric file: "
  160. + ne.getMessage());
  161. }
  162. } else if ("pair".equals(localName)) {
  163. currentKerning.put(new Integer(attributes.getValue("kpx2")),
  164. new Integer(attributes.getValue("kern")));
  165. }
  166. }
  167. private int getInt(String str) {
  168. int ret = 0;
  169. try {
  170. ret = Integer.parseInt(str);
  171. } catch (Exception e) {}
  172. return ret;
  173. }
  174. public void endElement(String uri, String localName, String qName) {
  175. if ("font-name".equals(localName))
  176. if (isCID)
  177. multiFont.fontName = text;
  178. else
  179. singleFont.fontName = text;
  180. if ("ttc-name".equals(localName) && isCID)
  181. multiFont.ttcName = text;
  182. else if ("cap-height".equals(localName))
  183. if (isCID)
  184. multiFont.capHeight = getInt(text);
  185. else
  186. singleFont.capHeight = getInt(text);
  187. else if ("x-height".equals(localName))
  188. if (isCID)
  189. multiFont.xHeight = getInt(text);
  190. else
  191. singleFont.xHeight = getInt(text);
  192. else if ("ascender".equals(localName))
  193. if (isCID)
  194. multiFont.ascender = getInt(text);
  195. else
  196. singleFont.ascender = getInt(text);
  197. else if ("descender".equals(localName))
  198. if (isCID)
  199. multiFont.descender = getInt(text);
  200. else
  201. singleFont.descender = getInt(text);
  202. else if ("left".equals(localName))
  203. if (isCID)
  204. multiFont.fontBBox[0] = getInt(text);
  205. else
  206. singleFont.fontBBox[0] = getInt(text);
  207. else if ("bottom".equals(localName))
  208. if (isCID)
  209. multiFont.fontBBox[1] = getInt(text);
  210. else
  211. singleFont.fontBBox[1] = getInt(text);
  212. else if ("right".equals(localName))
  213. if (isCID)
  214. multiFont.fontBBox[2] = getInt(text);
  215. else
  216. singleFont.fontBBox[2] = getInt(text);
  217. else if ("first-char".equals(localName))
  218. singleFont.firstChar = getInt(text);
  219. else if ("last-char".equals(localName))
  220. singleFont.lastChar = getInt(text);
  221. else if ("top".equals(localName))
  222. if (isCID)
  223. multiFont.fontBBox[3] = getInt(text);
  224. else
  225. singleFont.fontBBox[3] = getInt(text);
  226. else if ("flags".equals(localName))
  227. if (isCID)
  228. multiFont.flags = getInt(text);
  229. else
  230. singleFont.flags = getInt(text);
  231. else if ("stemv".equals(localName))
  232. if (isCID)
  233. multiFont.stemV = getInt(text);
  234. else
  235. singleFont.stemV = getInt(text);
  236. else if ("italic-angle".equals(localName))
  237. if (isCID)
  238. multiFont.italicAngle = getInt(text);
  239. else
  240. singleFont.italicAngle = getInt(text);
  241. else if ("missing-width".equals(localName))
  242. if (isCID)
  243. multiFont.missingWidth = getInt(text);
  244. else
  245. singleFont.missingWidth = getInt(text);
  246. else if ("cid-type".equals(localName)) {
  247. if ("CIDFontType2".equals(text))
  248. multiFont.cidType = PDFCIDFont.CID_TYPE2;
  249. } else if ("default-width".equals(localName)) {
  250. multiFont.defaultWidth = getInt(text);
  251. } else if ("cid-widths".equals(localName)) {
  252. int[] wds = new int[cidWidths.size()];
  253. int j = 0;
  254. for (int count = 0; count < cidWidths.size(); count++) {
  255. Integer i = (Integer)cidWidths.get(count);
  256. wds[j++] = i.intValue();
  257. }
  258. multiFont.warray.addEntry(cidWidthIndex, wds);
  259. multiFont.width = wds;
  260. } else if ("bfranges".equals(localName)) {
  261. multiFont.bfentries = (BFEntry[])bfranges.toArray(new BFEntry[0]);
  262. }
  263. }
  264. public void characters(char[] ch, int start, int length) {
  265. char c[] = new char[length];
  266. System.arraycopy(ch, start, c, 0, length);
  267. text = new String(c);
  268. }
  269. }