git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1882341 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_6
import org.apache.fop.fonts.CustomFont; | import org.apache.fop.fonts.CustomFont; | ||||
import org.apache.fop.fonts.Typeface; | import org.apache.fop.fonts.Typeface; | ||||
import org.apache.fop.fonts.truetype.GlyfTable; | |||||
import org.apache.fop.fonts.truetype.OFDirTabEntry; | |||||
import org.apache.fop.fonts.truetype.OFMtxEntry; | |||||
import org.apache.fop.fonts.truetype.OFTableName; | |||||
import org.apache.fop.render.java2d.CustomFontMetricsMapper; | import org.apache.fop.render.java2d.CustomFontMetricsMapper; | ||||
import org.apache.fop.util.CharUtilities; | |||||
public class PCLSoftFontManager { | public class PCLSoftFontManager { | ||||
private Map<Typeface, PCLFontReader> fontReaderMap; | private Map<Typeface, PCLFontReader> fontReaderMap; | ||||
} | } | ||||
public ByteArrayOutputStream makeSoftFont(Typeface font, String text) throws IOException { | public ByteArrayOutputStream makeSoftFont(Typeface font, String text) throws IOException { | ||||
List<Map<Character, Integer>> mappedGlyphs = mapFontGlyphs(font); | |||||
if (!fontReaderMap.containsKey(font)) { | if (!fontReaderMap.containsKey(font)) { | ||||
fontReaderMap.put(font, PCLFontReaderFactory.createInstance(font)); | fontReaderMap.put(font, PCLFontReaderFactory.createInstance(font)); | ||||
} | } | ||||
fontReader = fontReaderMap.get(font); | fontReader = fontReaderMap.get(font); | ||||
List<Map<Character, Integer>> mappedGlyphs = mapFontGlyphs(font); | |||||
if (mappedGlyphs.isEmpty()) { | if (mappedGlyphs.isEmpty()) { | ||||
mappedGlyphs.add(new HashMap<Character, Integer>()); | mappedGlyphs.add(new HashMap<Character, Integer>()); | ||||
} | } | ||||
return f; | return f; | ||||
} | } | ||||
private List<Map<Character, Integer>> mapFontGlyphs(Typeface tf) { | |||||
private List<Map<Character, Integer>> mapFontGlyphs(Typeface tf) throws IOException { | |||||
List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>(); | List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>(); | ||||
if (tf instanceof CustomFontMetricsMapper) { | if (tf instanceof CustomFontMetricsMapper) { | ||||
CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) tf; | CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) tf; | ||||
return mappedGlyphs; | return mappedGlyphs; | ||||
} | } | ||||
private List<Map<Character, Integer>> mapGlyphs(Map<Integer, Integer> usedGlyphs, CustomFont font) { | |||||
private List<Map<Character, Integer>> mapGlyphs(Map<Integer, Integer> usedGlyphs, CustomFont font) | |||||
throws IOException { | |||||
int charCount = 32; | int charCount = 32; | ||||
int charCountComposite = 32; | |||||
List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>(); | List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>(); | ||||
Map<Character, Integer> fontGlyphs = new HashMap<Character, Integer>(); | Map<Character, Integer> fontGlyphs = new HashMap<Character, Integer>(); | ||||
Map<Character, Integer> fontGlyphsComposite = new HashMap<Character, Integer>(); | |||||
for (Entry<Integer, Integer> entry : usedGlyphs.entrySet()) { | for (Entry<Integer, Integer> entry : usedGlyphs.entrySet()) { | ||||
int glyphID = entry.getKey(); | int glyphID = entry.getKey(); | ||||
if (glyphID == 0) { | if (glyphID == 0) { | ||||
charCount = 32; | charCount = 32; | ||||
fontGlyphs = new HashMap<Character, Integer>(); | fontGlyphs = new HashMap<Character, Integer>(); | ||||
} | } | ||||
fontGlyphs.put(unicode, charCount++); | |||||
if (isComposite(font, unicode)) { | |||||
fontGlyphsComposite.put(unicode, charCountComposite++); | |||||
} else { | |||||
fontGlyphs.put(unicode, charCount++); | |||||
} | |||||
} | } | ||||
if (fontGlyphs.size() > 0) { | if (fontGlyphs.size() > 0) { | ||||
mappedGlyphs.add(fontGlyphs); | mappedGlyphs.add(fontGlyphs); | ||||
} | } | ||||
if (fontGlyphsComposite.size() > 0) { | |||||
mappedGlyphs.add(fontGlyphsComposite); | |||||
} | |||||
return mappedGlyphs; | return mappedGlyphs; | ||||
} | } | ||||
private boolean isComposite(CustomFont customFont, int unicode) throws IOException { | |||||
OFDirTabEntry glyfTableInfo = fontReader.getFontFile().getDirectoryEntry(OFTableName.GLYF); | |||||
if (glyfTableInfo == null) { | |||||
return false; | |||||
} | |||||
List<OFMtxEntry> mtx = fontReader.getFontFile().getMtx(); | |||||
Map<Integer, Integer> subsetGlyphs = customFont.getUsedGlyphs(); | |||||
GlyfTable glyfTable = new GlyfTable(fontReader.getFontFileReader(), mtx.toArray(new OFMtxEntry[mtx.size()]), | |||||
glyfTableInfo, subsetGlyphs); | |||||
Map<Integer, Integer> mtxCharacters = fontReader.scanMtxCharacters(); | |||||
if (mtxCharacters.containsKey(unicode)) { | |||||
int mtxChar = mtxCharacters.get(unicode); | |||||
return glyfTable.isComposite(mtxChar); | |||||
} | |||||
return false; | |||||
} | |||||
private void writeFontID(int fontID, OutputStream os) throws IOException { | private void writeFontID(int fontID, OutputStream os) throws IOException { | ||||
os.write(assignFontID(fontID)); | os.write(assignFontID(fontID)); | ||||
} | } | ||||
int curFontID = -1; | int curFontID = -1; | ||||
String current = ""; | String current = ""; | ||||
for (char ch : text.toCharArray()) { | for (char ch : text.toCharArray()) { | ||||
if (ch == CharUtilities.NBSPACE) { | |||||
ch = ' '; | |||||
} | |||||
for (PCLSoftFont softFont : fonts) { | for (PCLSoftFont softFont : fonts) { | ||||
if (curFontID == -1) { | if (curFontID == -1) { | ||||
curFontID = softFont.getFontID(); | curFontID = softFont.getFontID(); |
import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.io.UnsupportedEncodingException; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.List; | import java.util.List; | ||||
} | } | ||||
private void writeTrueTypeTable(ByteArrayOutputStream baos, OFTableName table, | private void writeTrueTypeTable(ByteArrayOutputStream baos, OFTableName table, | ||||
List<TableOffset> tableOffsets) throws IOException, UnsupportedEncodingException { | |||||
List<TableOffset> tableOffsets) throws IOException { | |||||
OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(table); | OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(table); | ||||
if (tabEntry != null) { | if (tabEntry != null) { | ||||
baos.write(tabEntry.getTag()); | baos.write(tabEntry.getTag()); | ||||
} | } | ||||
} | } | ||||
private void writeGDIR(ByteArrayOutputStream baos) throws UnsupportedEncodingException, IOException { | |||||
private void writeGDIR(ByteArrayOutputStream baos) throws IOException { | |||||
baos.write("gdir".getBytes("ISO-8859-1")); | baos.write("gdir".getBytes("ISO-8859-1")); | ||||
baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Checksum | baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Checksum | ||||
baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Offset | baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Offset | ||||
return (int) sum; | return (int) sum; | ||||
} | } | ||||
protected byte[] createHmtx(Map<Character, Integer> mappedGlyphs) throws IOException { | |||||
protected byte[] createHmtx(Map<Character, Integer> mappedGlyphs) { | |||||
byte[] hmtxTable = new byte[((mappedGlyphs.size() + 32) * 4)]; | byte[] hmtxTable = new byte[((mappedGlyphs.size() + 32) * 4)]; | ||||
OFDirTabEntry entry = ttfFont.getDirectoryEntry(OFTableName.HMTX); | OFDirTabEntry entry = ttfFont.getDirectoryEntry(OFTableName.HMTX); | ||||
if (entry != null) { | if (entry != null) { | ||||
for (Entry<Character, Integer> glyphSubset : mappedGlyphs.entrySet()) { | for (Entry<Character, Integer> glyphSubset : mappedGlyphs.entrySet()) { | ||||
char unicode = glyphSubset.getKey(); | char unicode = glyphSubset.getKey(); | ||||
int originalIndex = 0; | |||||
int softFontGlyphIndex = glyphSubset.getValue(); | int softFontGlyphIndex = glyphSubset.getValue(); | ||||
if (font instanceof MultiByteFont) { | if (font instanceof MultiByteFont) { | ||||
originalIndex = ((MultiByteFont) font).getGIDFromChar(unicode); | |||||
writeUShort(hmtxTable, (softFontGlyphIndex) * 4, | |||||
int originalIndex = ((MultiByteFont) font).getGIDFromChar(unicode); | |||||
writeUShort(hmtxTable, softFontGlyphIndex * 4, | |||||
ttfFont.getMtx().get(originalIndex).getWx()); | ttfFont.getMtx().get(originalIndex).getWx()); | ||||
writeUShort(hmtxTable, (softFontGlyphIndex) * 4 + 2, | |||||
writeUShort(hmtxTable, softFontGlyphIndex * 4 + 2, | |||||
ttfFont.getMtx().get(originalIndex).getLsb()); | ttfFont.getMtx().get(originalIndex).getLsb()); | ||||
} else { | } else { | ||||
originalIndex = ((SingleByteFont) font).getGIDFromChar(unicode); | |||||
writeUShort(hmtxTable, (softFontGlyphIndex) * 4, | |||||
int originalIndex = ((SingleByteFont) font).getGIDFromChar(unicode); | |||||
writeUShort(hmtxTable, softFontGlyphIndex * 4, | |||||
font.getWidth(originalIndex, 1)); | font.getWidth(originalIndex, 1)); | ||||
writeUShort(hmtxTable, (softFontGlyphIndex) * 4 + 2, 0); | |||||
writeUShort(hmtxTable, softFontGlyphIndex * 4 + 2, 0); | |||||
} | } | ||||
} | } | ||||
} | } |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.render.pcl.fonts; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | |||||
import java.net.URI; | |||||
import java.util.HashMap; | |||||
import org.junit.Assert; | |||||
import org.junit.Test; | |||||
import org.apache.fop.apps.FOUserAgent; | |||||
import org.apache.fop.apps.FopFactory; | |||||
import org.apache.fop.fonts.CMapSegment; | |||||
import org.apache.fop.fonts.EmbeddingMode; | |||||
import org.apache.fop.fonts.FontType; | |||||
import org.apache.fop.fonts.MultiByteFont; | |||||
import org.apache.fop.render.java2d.CustomFontMetricsMapper; | |||||
public class PCLSoftFontManagerTestCase { | |||||
@Test | |||||
public void testSplitCompositeGlyphs() throws Exception { | |||||
FOUserAgent ua = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent(); | |||||
PCLSoftFontManager pclSoftFontManager = new PCLSoftFontManager(new HashMap()); | |||||
MultiByteFont mbf = new MultiByteFont(ua.getResourceResolver(), EmbeddingMode.SUBSET); | |||||
mbf.setEmbedURI(new URI("test/resources/fonts/ttf/DejaVuLGCSerif.ttf")); | |||||
mbf.setFontType(FontType.TRUETYPE); | |||||
CMapSegment cMapSegment1 = new CMapSegment('a', 'a', 1); | |||||
CMapSegment cMapSegment2 = new CMapSegment('\u00E0', '\u00E0', 2); | |||||
mbf.setCMap(new CMapSegment[] {cMapSegment1, cMapSegment2}); | |||||
mbf.mapChar('a'); | |||||
mbf.mapChar('\u00E0'); | |||||
CustomFontMetricsMapper font = new CustomFontMetricsMapper(mbf); | |||||
ByteArrayOutputStream bos = pclSoftFontManager.makeSoftFont(font, ""); | |||||
String[] fontStrings = bos.toString().split("DejaVu changes are in public domain"); | |||||
Assert.assertEquals(fontStrings.length, 3); | |||||
} | |||||
} |