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.

Type1FontFormatter.java 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. package org.apache.fop.render.ps;
  18. import java.io.IOException;
  19. import java.text.DecimalFormat;
  20. import java.text.DecimalFormatSymbols;
  21. import java.text.NumberFormat;
  22. import java.util.Collection;
  23. import java.util.Locale;
  24. import java.util.Map;
  25. import org.apache.fontbox.cff.CFFType1Font;
  26. import org.apache.fontbox.cff.DataOutput;
  27. import org.apache.fontbox.cff.Type1FontUtil;
  28. /**
  29. * This class represents a formatter for a given Type1 font.
  30. * author Villu Ruusmann
  31. * @version $Revision: 1.0 $
  32. */
  33. public final class Type1FontFormatter {
  34. private Map<Integer, Integer> gids;
  35. public Type1FontFormatter(Map<Integer, Integer> gids) {
  36. this.gids = gids;
  37. }
  38. /**
  39. * Read and convert a given CFFFont.
  40. * @param font the given CFFFont
  41. * @param i
  42. * @return the Type1 font
  43. * @throws IOException if an error occurs during reading the given font
  44. */
  45. public byte[] format(CFFType1Font font, String i) throws IOException {
  46. DataOutput output = new DataOutput();
  47. printFont(font, output, i);
  48. return output.getBytes();
  49. }
  50. private void printFont(CFFType1Font font, DataOutput output, String iStr)
  51. throws IOException {
  52. output.println("%!FontType1-1.0 " + font.getName() + iStr + " "
  53. + font.getTopDict().get("version"));
  54. printFontDictionary(font, output, iStr);
  55. for (int i = 0; i < 8; i++) {
  56. StringBuilder sb = new StringBuilder();
  57. for (int j = 0; j < 64; j++) {
  58. sb.append("0");
  59. }
  60. output.println(sb.toString());
  61. }
  62. output.println("cleartomark");
  63. }
  64. private void printFontDictionary(CFFType1Font font, DataOutput output, String iStr)
  65. throws IOException {
  66. output.println("10 dict begin");
  67. output.println("/FontInfo 10 dict dup begin");
  68. output.println("/version (" + font.getTopDict().get("version")
  69. + ") readonly def");
  70. output.println("/Notice (" + font.getTopDict().get("Notice")
  71. + ") readonly def");
  72. output.println("/FullName (" + font.getTopDict().get("FullName")
  73. + ") readonly def");
  74. output.println("/FamilyName (" + font.getTopDict().get("FamilyName")
  75. + ") readonly def");
  76. output.println("/Weight (" + font.getTopDict().get("Weight")
  77. + ") readonly def");
  78. output.println("/ItalicAngle " + font.getTopDict().get("ItalicAngle")
  79. + " def");
  80. output.println("/isFixedPitch " + font.getTopDict().get("isFixedPitch")
  81. + " def");
  82. output.println("/UnderlinePosition "
  83. + font.getTopDict().get("UnderlinePosition") + " def");
  84. output.println("/UnderlineThickness "
  85. + font.getTopDict().get("UnderlineThickness") + " def");
  86. output.println("end readonly def");
  87. output.println("/FontName /" + font.getName() + iStr + " def");
  88. output.println("/PaintType " + font.getTopDict().get("PaintType") + " def");
  89. output.println("/FontType 1 def");
  90. NumberFormat matrixFormat = new DecimalFormat("0.########", new DecimalFormatSymbols(Locale.US));
  91. output.println("/FontMatrix "
  92. + formatArray(font.getTopDict().get("FontMatrix"), matrixFormat, false)
  93. + " readonly def");
  94. output.println("/FontBBox "
  95. + formatArray(font.getTopDict().get("FontBBox"), false)
  96. + " readonly def");
  97. output.println("/StrokeWidth " + font.getTopDict().get("StrokeWidth")
  98. + " def");
  99. int max = 0;
  100. StringBuilder sb = new StringBuilder();
  101. for (Map.Entry<Integer, Integer> gid : gids.entrySet()) {
  102. String name = font.getCharset().getNameForGID(gid.getKey());
  103. sb.append(String.format("dup %d /%s put", gid.getValue(), name)).append('\n');
  104. max = Math.max(max, gid.getValue());
  105. }
  106. output.println("/Encoding " + (max + 1) + " array");
  107. output.println("0 1 " + max + " {1 index exch /.notdef put} for");
  108. output.print(sb.toString());
  109. output.println("readonly def");
  110. output.println("currentdict end");
  111. DataOutput eexecOutput = new DataOutput();
  112. printEexecFontDictionary(font, eexecOutput);
  113. output.println("currentfile eexec");
  114. byte[] eexecBytes = Type1FontUtil.eexecEncrypt(eexecOutput.getBytes());
  115. output.write(eexecBytes);
  116. }
  117. private void printEexecFontDictionary(CFFType1Font font, DataOutput output)
  118. throws IOException {
  119. output.println("dup /Private 15 dict dup begin");
  120. output.println("/RD {string currentfile exch readstring pop} executeonly def");
  121. output.println("/ND {noaccess def} executeonly def");
  122. output.println("/NP {noaccess put} executeonly def");
  123. output.println("/BlueValues "
  124. + formatArray(font.getPrivateDict().get("BlueValues"), true) + " ND");
  125. output.println("/OtherBlues "
  126. + formatArray(font.getPrivateDict().get("OtherBlues"), true) + " ND");
  127. output.println("/BlueScale " + font.getPrivateDict().get("BlueScale") + " def");
  128. output.println("/BlueShift " + font.getPrivateDict().get("BlueShift") + " def");
  129. output.println("/BlueFuzz " + font.getPrivateDict().get("BlueFuzz") + " def");
  130. output.println("/StdHW " + formatArray(font.getPrivateDict().get("StdHW"), true)
  131. + " ND");
  132. output.println("/StdVW " + formatArray(font.getPrivateDict().get("StdVW"), true)
  133. + " ND");
  134. output.println("/ForceBold " + font.getPrivateDict().get("ForceBold") + " def");
  135. output.println("/MinFeature {16 16} def");
  136. output.println("/password 5839 def");
  137. output.println("2 index /CharStrings " + gids.size() + " dict dup begin");
  138. Type1CharStringFormatter formatter = new Type1CharStringFormatter();
  139. for (int gid : gids.keySet()) {
  140. String mapping = font.getCharset().getNameForGID(gid);
  141. byte[] type1Bytes = formatter.format(font.getType1CharString(mapping).getType1Sequence());
  142. byte[] charstringBytes = Type1FontUtil.charstringEncrypt(type1Bytes, 4);
  143. output.print("/" + mapping + " " + charstringBytes.length + " RD ");
  144. output.write(charstringBytes);
  145. output.print(" ND");
  146. output.println();
  147. }
  148. output.println("end");
  149. output.println("end");
  150. output.println("readonly put");
  151. output.println("noaccess put");
  152. output.println("dup /FontName get exch definefont pop");
  153. output.println("mark currentfile closefile");
  154. }
  155. private static String formatArray(Object object, boolean executable) {
  156. return formatArray(object, null, executable);
  157. }
  158. private static String formatArray(Object object, NumberFormat format, boolean executable) {
  159. StringBuffer sb = new StringBuffer();
  160. sb.append(executable ? "{" : "[");
  161. if (object instanceof Collection) {
  162. String sep = "";
  163. Collection<?> elements = (Collection<?>) object;
  164. for (Object element : elements) {
  165. sb.append(sep).append(formatElement(element, format));
  166. sep = " ";
  167. }
  168. } else if (object instanceof Number) {
  169. sb.append(formatElement(object, format));
  170. }
  171. sb.append(executable ? "}" : "]");
  172. return sb.toString();
  173. }
  174. private static String formatElement(Object object, NumberFormat format) {
  175. if (format != null) {
  176. if (object instanceof Double || object instanceof Float) {
  177. Number number = (Number)object;
  178. return format.format(number.doubleValue());
  179. } else if (object instanceof Long || object instanceof Integer) {
  180. Number number = (Number)object;
  181. return format.format(number.longValue());
  182. }
  183. }
  184. return String.valueOf(object);
  185. }
  186. }