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.

PSFontUtils.java 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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.render.ps;
  19. import java.io.FileNotFoundException;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.net.MalformedURLException;
  23. import java.util.Iterator;
  24. import java.util.Map;
  25. import javax.xml.transform.Source;
  26. import javax.xml.transform.stream.StreamSource;
  27. import org.apache.commons.logging.Log;
  28. import org.apache.commons.logging.LogFactory;
  29. import org.apache.xmlgraphics.ps.DSCConstants;
  30. import org.apache.xmlgraphics.ps.PSGenerator;
  31. import org.apache.xmlgraphics.ps.PSResource;
  32. import org.apache.xmlgraphics.ps.dsc.ResourceTracker;
  33. import org.apache.fop.fonts.CustomFont;
  34. import org.apache.fop.fonts.Font;
  35. import org.apache.fop.fonts.FontInfo;
  36. import org.apache.fop.fonts.FontType;
  37. import org.apache.fop.fonts.LazyFont;
  38. import org.apache.fop.fonts.Typeface;
  39. /**
  40. * Utility code for font handling in PostScript.
  41. */
  42. public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils {
  43. /** logging instance */
  44. protected static Log log = LogFactory.getLog(PSFontUtils.class);
  45. /**
  46. * Generates the PostScript code for the font dictionary.
  47. * @param gen PostScript generator to use for output
  48. * @param fontInfo available fonts
  49. * @return a Map of PSResource instances representing all defined fonts (key: font key)
  50. * @throws IOException in case of an I/O problem
  51. */
  52. public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo)
  53. throws IOException {
  54. return writeFontDict(gen, fontInfo, fontInfo.getFonts());
  55. }
  56. /**
  57. * Generates the PostScript code for the font dictionary.
  58. * @param gen PostScript generator to use for output
  59. * @param fontInfo available fonts
  60. * @param fonts the set of fonts to work with
  61. * @return a Map of PSResource instances representing all defined fonts (key: font key)
  62. * @throws IOException in case of an I/O problem
  63. */
  64. public static Map writeFontDict(PSGenerator gen, FontInfo fontInfo, Map fonts)
  65. throws IOException {
  66. gen.commentln("%FOPBeginFontDict");
  67. Map fontResources = new java.util.HashMap();
  68. Iterator iter = fonts.keySet().iterator();
  69. while (iter.hasNext()) {
  70. String key = (String)iter.next();
  71. Typeface tf = getTypeFace(fontInfo, fonts, key);
  72. PSResource fontRes = new PSResource("font", tf.getFontName());
  73. fontResources.put(key, fontRes);
  74. embedFont(gen, tf, fontRes);
  75. }
  76. gen.commentln("%FOPEndFontDict");
  77. reencodeFonts(gen, fonts);
  78. return fontResources;
  79. }
  80. private static void reencodeFonts(PSGenerator gen, Map fonts) throws IOException {
  81. gen.commentln("%FOPBeginFontReencode");
  82. defineWinAnsiEncoding(gen);
  83. //Rewrite font encodings
  84. Iterator iter = fonts.keySet().iterator();
  85. while (iter.hasNext()) {
  86. String key = (String)iter.next();
  87. Typeface fm = (Typeface)fonts.get(key);
  88. if (fm instanceof LazyFont && ((LazyFont)fm).getRealFont() == null) {
  89. continue;
  90. } else if (null == fm.getEncoding()) {
  91. //ignore (ZapfDingbats and Symbol used to run through here, kept for safety reasons)
  92. } else if ("SymbolEncoding".equals(fm.getEncoding())) {
  93. //ignore (no encoding redefinition)
  94. } else if ("ZapfDingbatsEncoding".equals(fm.getEncoding())) {
  95. //ignore (no encoding redefinition)
  96. } else if ("WinAnsiEncoding".equals(fm.getEncoding())) {
  97. redefineFontEncoding(gen, fm.getFontName(), fm.getEncoding());
  98. } else {
  99. /* Don't complain anymore, just use the font's default encoding.
  100. gen.commentln("%WARNING: Only WinAnsiEncoding is supported. Font '"
  101. + fm.getFontName() + "' asks for: " + fm.getEncoding());
  102. */
  103. }
  104. }
  105. gen.commentln("%FOPEndFontReencode");
  106. }
  107. private static Typeface getTypeFace(FontInfo fontInfo, Map fonts, String key) {
  108. Typeface tf = (Typeface)fonts.get(key);
  109. if (tf instanceof LazyFont) {
  110. tf = ((LazyFont)tf).getRealFont();
  111. }
  112. if (tf == null) {
  113. //This is to avoid an NPE if a malconfigured font is in the configuration but not
  114. //used in the document. If it were used, we wouldn't get this far.
  115. String fallbackKey = fontInfo.getInternalFontKey(Font.DEFAULT_FONT);
  116. tf = (Typeface)fonts.get(fallbackKey);
  117. }
  118. return tf;
  119. }
  120. /**
  121. * Embeds a font in the PostScript file.
  122. * @param gen the PostScript generator
  123. * @param tf the font
  124. * @param fontRes the PSResource associated with the font
  125. * @throws IOException In case of an I/O error
  126. */
  127. public static void embedFont(PSGenerator gen, Typeface tf, PSResource fontRes)
  128. throws IOException {
  129. boolean embeddedFont = false;
  130. if (FontType.TYPE1 == tf.getFontType()) {
  131. if (tf instanceof CustomFont) {
  132. CustomFont cf = (CustomFont)tf;
  133. if (isEmbeddable(cf)) {
  134. InputStream in = getInputStreamOnFont(gen, cf);
  135. if (in != null) {
  136. gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE,
  137. fontRes);
  138. embedType1Font(gen, in);
  139. gen.writeDSCComment(DSCConstants.END_RESOURCE);
  140. gen.getResourceTracker().registerSuppliedResource(fontRes);
  141. embeddedFont = true;
  142. } else {
  143. gen.commentln("%WARNING: Could not embed font: " + cf.getFontName());
  144. log.warn("Font " + cf.getFontName() + " is marked as supplied in the"
  145. + " PostScript file but could not be embedded!");
  146. }
  147. }
  148. }
  149. }
  150. if (!embeddedFont) {
  151. gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes);
  152. }
  153. }
  154. private static boolean isEmbeddable(CustomFont font) {
  155. return font.isEmbeddable()
  156. && (font.getEmbedFileName() != null || font.getEmbedResourceName() != null);
  157. }
  158. private static InputStream getInputStreamOnFont(PSGenerator gen, CustomFont font)
  159. throws IOException {
  160. if (isEmbeddable(font)) {
  161. Source source = font.getEmbedFileSource();
  162. if (source == null && font.getEmbedResourceName() != null) {
  163. source = new StreamSource(PSFontUtils.class
  164. .getResourceAsStream(font.getEmbedResourceName()));
  165. }
  166. if (source == null) {
  167. return null;
  168. }
  169. InputStream in = null;
  170. if (source instanceof StreamSource) {
  171. in = ((StreamSource) source).getInputStream();
  172. }
  173. if (in == null && source.getSystemId() != null) {
  174. try {
  175. in = new java.net.URL(source.getSystemId()).openStream();
  176. } catch (MalformedURLException e) {
  177. new FileNotFoundException(
  178. "File not found. URL could not be resolved: "
  179. + e.getMessage());
  180. }
  181. }
  182. if (in == null) {
  183. return null;
  184. }
  185. //Make sure the InputStream is decorated with a BufferedInputStream
  186. if (!(in instanceof java.io.BufferedInputStream)) {
  187. in = new java.io.BufferedInputStream(in);
  188. }
  189. return in;
  190. } else {
  191. return null;
  192. }
  193. }
  194. /**
  195. * Determines the set of fonts that will be supplied with the PS file and registers them
  196. * with the resource tracker. All the fonts that are being processed are returned as a Map.
  197. * @param resTracker the resource tracker
  198. * @param fontInfo available fonts
  199. * @param fonts the set of fonts to work with
  200. * @return a Map of PSResource instances representing all defined fonts (key: font key)
  201. */
  202. public static Map determineSuppliedFonts(ResourceTracker resTracker,
  203. FontInfo fontInfo, Map fonts) {
  204. Map fontResources = new java.util.HashMap();
  205. Iterator iter = fonts.keySet().iterator();
  206. while (iter.hasNext()) {
  207. String key = (String)iter.next();
  208. Typeface tf = getTypeFace(fontInfo, fonts, key);
  209. PSResource fontRes = new PSResource("font", tf.getFontName());
  210. fontResources.put(key, fontRes);
  211. if (FontType.TYPE1 == tf.getFontType()) {
  212. if (tf instanceof CustomFont) {
  213. CustomFont cf = (CustomFont)tf;
  214. if (isEmbeddable(cf)) {
  215. resTracker.registerSuppliedResource(fontRes);
  216. }
  217. }
  218. }
  219. }
  220. return fontResources;
  221. }
  222. }