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.

PCLTTFCharacterWriter.java 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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.pcl.fonts.truetype;
  19. import java.io.ByteArrayOutputStream;
  20. import java.io.IOException;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Set;
  25. import org.apache.fop.fonts.truetype.GlyfTable;
  26. import org.apache.fop.fonts.truetype.OFDirTabEntry;
  27. import org.apache.fop.fonts.truetype.OFMtxEntry;
  28. import org.apache.fop.fonts.truetype.OFTableName;
  29. import org.apache.fop.fonts.truetype.TTFFile;
  30. import org.apache.fop.render.pcl.fonts.PCLCharacterDefinition;
  31. import org.apache.fop.render.pcl.fonts.PCLCharacterDefinition.PCLCharacterClass;
  32. import org.apache.fop.render.pcl.fonts.PCLCharacterDefinition.PCLCharacterFormat;
  33. import org.apache.fop.render.pcl.fonts.PCLCharacterWriter;
  34. import org.apache.fop.render.pcl.fonts.PCLSoftFont;
  35. public class PCLTTFCharacterWriter extends PCLCharacterWriter {
  36. private List<OFMtxEntry> mtx;
  37. private OFDirTabEntry tabEntry;
  38. public PCLTTFCharacterWriter(PCLSoftFont softFont) throws IOException {
  39. super(softFont);
  40. softFont.setMtxCharIndexes(scanMtxCharacters());
  41. }
  42. @Override
  43. public byte[] writeCharacterDefinitions(String text) throws IOException {
  44. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  45. for (char ch : text.toCharArray()) {
  46. int character = (int) ch;
  47. if (!font.hasPreviouslyWritten(character)) {
  48. PCLCharacterDefinition pclChar = getCharacterDefinition(ch);
  49. writePCLCharacter(baos, pclChar);
  50. List<PCLCharacterDefinition> compositeGlyphs = pclChar.getCompositeGlyphs();
  51. for (PCLCharacterDefinition composite : compositeGlyphs) {
  52. writePCLCharacter(baos, composite);
  53. }
  54. }
  55. }
  56. return baos.toByteArray();
  57. }
  58. private void writePCLCharacter(ByteArrayOutputStream baos, PCLCharacterDefinition pclChar) throws IOException {
  59. baos.write(pclChar.getCharacterCommand());
  60. baos.write(pclChar.getCharacterDefinitionCommand());
  61. baos.write(pclChar.getData());
  62. }
  63. private Map<Integer, Integer> scanMtxCharacters() throws IOException {
  64. Map<Integer, Integer> charMtxOffsets = new HashMap<Integer, Integer>();
  65. List<OFMtxEntry> mtx = openFont.getMtx();
  66. OFTableName glyfTag = OFTableName.GLYF;
  67. if (openFont.seekTab(fontReader, glyfTag, 0)) {
  68. for (int i = 1; i < mtx.size(); i++) {
  69. OFMtxEntry entry = mtx.get(i);
  70. int charCode = 0;
  71. if (entry.getUnicodeIndex().size() > 0) {
  72. charCode = (Integer) entry.getUnicodeIndex().get(0);
  73. } else {
  74. charCode = entry.getIndex();
  75. }
  76. charMtxOffsets.put(charCode, i);
  77. }
  78. }
  79. return charMtxOffsets;
  80. }
  81. private PCLCharacterDefinition getCharacterDefinition(int unicode) throws IOException {
  82. if (mtx == null) {
  83. mtx = openFont.getMtx();
  84. tabEntry = openFont.getDirectoryEntry(OFTableName.GLYF);
  85. }
  86. if (openFont.seekTab(fontReader, OFTableName.GLYF, 0)) {
  87. int charIndex = font.getMtxCharIndex(unicode);
  88. // Fallback - only works for MultiByte fonts
  89. if (charIndex == 0) {
  90. charIndex = font.getCmapGlyphIndex(unicode);
  91. }
  92. Map<Integer, Integer> subsetGlyphs = new HashMap<Integer, Integer>();
  93. subsetGlyphs.put(charIndex, 1);
  94. byte[] glyphData = getGlyphData(charIndex);
  95. font.writeCharacter(unicode);
  96. PCLCharacterDefinition newChar = new PCLCharacterDefinition(
  97. font.getCharCode((char) unicode),
  98. PCLCharacterFormat.TrueType,
  99. PCLCharacterClass.TrueType, glyphData, pclByteWriter, false);
  100. // Handle composite character definitions
  101. GlyfTable glyfTable = new GlyfTable(fontReader, mtx.toArray(new OFMtxEntry[mtx.size()]),
  102. tabEntry, subsetGlyphs);
  103. if (glyfTable.isComposite(charIndex)) {
  104. Set<Integer> composites = glyfTable.retrieveComposedGlyphs(charIndex);
  105. for (Integer compositeIndex : composites) {
  106. byte[] compositeData = getGlyphData(compositeIndex);
  107. newChar.addCompositeGlyph(new PCLCharacterDefinition(compositeIndex,
  108. PCLCharacterFormat.TrueType,
  109. PCLCharacterClass.TrueType, compositeData, pclByteWriter, true));
  110. }
  111. }
  112. return newChar;
  113. }
  114. return null;
  115. }
  116. private byte[] getGlyphData(int charIndex) throws IOException {
  117. OFMtxEntry entry = mtx.get(charIndex);
  118. OFMtxEntry nextEntry;
  119. int nextOffset = 0;
  120. if (charIndex < mtx.size() - 1) {
  121. nextEntry = mtx.get(charIndex + 1);
  122. nextOffset = (int) nextEntry.getOffset();
  123. } else {
  124. nextOffset = (int) ((TTFFile) openFont).getLastGlyfLocation();
  125. }
  126. int glyphOffset = (int) entry.getOffset();
  127. int glyphLength = nextOffset - glyphOffset;
  128. byte[] glyphData = new byte[0];
  129. if (glyphLength > 0) {
  130. glyphData = fontReader.getBytes((int) tabEntry.getOffset() + glyphOffset, glyphLength);
  131. }
  132. return glyphData;
  133. }
  134. }