git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1792597 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_3
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public boolean isMultiByte() { | public boolean isMultiByte() { | ||||
return true; | |||||
return getFontType() != FontType.TYPE1C; | |||||
} | } | ||||
} | } |
package org.apache.fop.fonts; | package org.apache.fop.fonts; | ||||
import java.awt.Rectangle; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.net.URI; | import java.net.URI; | ||||
protected List<CMapSegment> cmap = new ArrayList<CMapSegment>(); | protected List<CMapSegment> cmap = new ArrayList<CMapSegment>(); | ||||
private boolean useAdvanced = true; | private boolean useAdvanced = true; | ||||
private boolean simulateStyle; | private boolean simulateStyle; | ||||
protected List<SimpleSingleByteEncoding> additionalEncodings; | |||||
protected Map<Character, SingleByteFont.UnencodedCharacter> unencodedCharacters; | |||||
/** | /** | ||||
* @param resourceResolver the URI resource resolver for controlling file access | * @param resourceResolver the URI resource resolver for controlling file access | ||||
* @return The character | * @return The character | ||||
*/ | */ | ||||
public abstract char getUnicodeFromGID(int glyphIndex); | public abstract char getUnicodeFromGID(int glyphIndex); | ||||
/** | |||||
* Indicates whether the encoding has additional encodings besides the primary encoding. | |||||
* @return true if there are additional encodings. | |||||
*/ | |||||
public boolean hasAdditionalEncodings() { | |||||
return (this.additionalEncodings != null) && (this.additionalEncodings.size() > 0); | |||||
} | |||||
/** | |||||
* Returns the number of additional encodings this single-byte font maintains. | |||||
* @return the number of additional encodings | |||||
*/ | |||||
public int getAdditionalEncodingCount() { | |||||
if (hasAdditionalEncodings()) { | |||||
return this.additionalEncodings.size(); | |||||
} else { | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* Returns an additional encoding. | |||||
* @param index the index of the additional encoding | |||||
* @return the additional encoding | |||||
* @throws IndexOutOfBoundsException if the index is out of bounds | |||||
*/ | |||||
public SimpleSingleByteEncoding getAdditionalEncoding(int index) | |||||
throws IndexOutOfBoundsException { | |||||
if (hasAdditionalEncodings()) { | |||||
return this.additionalEncodings.get(index); | |||||
} else { | |||||
throw new IndexOutOfBoundsException("No additional encodings available"); | |||||
} | |||||
} | |||||
/** | |||||
* Adds an unencoded character (one that is not supported by the primary encoding). | |||||
* @param ch the named character | |||||
* @param width the width of the character | |||||
*/ | |||||
public void addUnencodedCharacter(NamedCharacter ch, int width, Rectangle bbox) { | |||||
if (this.unencodedCharacters == null) { | |||||
this.unencodedCharacters = new HashMap<Character, SingleByteFont.UnencodedCharacter>(); | |||||
} | |||||
if (ch.hasSingleUnicodeValue()) { | |||||
SingleByteFont.UnencodedCharacter uc = new SingleByteFont.UnencodedCharacter(ch, width, bbox); | |||||
this.unencodedCharacters.put(ch.getSingleUnicodeValue(), uc); | |||||
} else { | |||||
//Cannot deal with unicode sequences, so ignore this character | |||||
} | |||||
} | |||||
/** | |||||
* Adds a character to additional encodings | |||||
* @param ch character to map | |||||
*/ | |||||
protected char mapUnencodedChar(char ch) { | |||||
if (this.unencodedCharacters != null) { | |||||
SingleByteFont.UnencodedCharacter unencoded = this.unencodedCharacters.get(ch); | |||||
if (unencoded != null) { | |||||
if (this.additionalEncodings == null) { | |||||
this.additionalEncodings = new ArrayList<SimpleSingleByteEncoding>(); | |||||
} | |||||
SimpleSingleByteEncoding encoding = null; | |||||
char mappedStart = 0; | |||||
int additionalsCount = this.additionalEncodings.size(); | |||||
for (int i = 0; i < additionalsCount; i++) { | |||||
mappedStart += 256; | |||||
encoding = getAdditionalEncoding(i); | |||||
char alt = encoding.mapChar(ch); | |||||
if (alt != 0) { | |||||
return (char)(mappedStart + alt); | |||||
} | |||||
} | |||||
if (encoding != null && encoding.isFull()) { | |||||
encoding = null; | |||||
} | |||||
if (encoding == null) { | |||||
encoding = new SimpleSingleByteEncoding( | |||||
getFontName() + "EncodingSupp" + (additionalsCount + 1)); | |||||
this.additionalEncodings.add(encoding); | |||||
mappedStart += 256; | |||||
} | |||||
return (char)(mappedStart + encoding.addCharacter(unencoded.getCharacter())); | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
} | } |
if (isEmbeddable()) { | if (isEmbeddable()) { | ||||
glyphIndex = cidSet.mapChar(glyphIndex, c); | glyphIndex = cidSet.mapChar(glyphIndex, c); | ||||
} | } | ||||
if (isCID() && glyphIndex > 256) { | |||||
mapUnencodedChar(c); | |||||
} | |||||
return (char) glyphIndex; | return (char) glyphIndex; | ||||
} | } | ||||
package org.apache.fop.fonts; | package org.apache.fop.fonts; | ||||
import java.awt.Rectangle; | import java.awt.Rectangle; | ||||
import java.util.ArrayList; | |||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.LinkedHashMap; | import java.util.LinkedHashMap; | ||||
import java.util.List; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.TreeSet; | import java.util.TreeSet; | ||||
private Rectangle[] boundingBoxes; | private Rectangle[] boundingBoxes; | ||||
private Map<Character, UnencodedCharacter> unencodedCharacters; | |||||
private List<SimpleSingleByteEncoding> additionalEncodings; | |||||
private Map<Character, Character> alternativeCodes; | private Map<Character, Character> alternativeCodes; | ||||
private PostScriptVersion ttPostScriptVersion; | private PostScriptVersion ttPostScriptVersion; | ||||
} | } | ||||
} | } | ||||
private char mapUnencodedChar(char ch) { | |||||
if (this.unencodedCharacters != null) { | |||||
UnencodedCharacter unencoded = this.unencodedCharacters.get(ch); | |||||
if (unencoded != null) { | |||||
if (this.additionalEncodings == null) { | |||||
this.additionalEncodings = new ArrayList<SimpleSingleByteEncoding>(); | |||||
} | |||||
SimpleSingleByteEncoding encoding = null; | |||||
char mappedStart = 0; | |||||
int additionalsCount = this.additionalEncodings.size(); | |||||
for (int i = 0; i < additionalsCount; i++) { | |||||
mappedStart += 256; | |||||
encoding = getAdditionalEncoding(i); | |||||
char alt = encoding.mapChar(ch); | |||||
if (alt != 0) { | |||||
return (char)(mappedStart + alt); | |||||
} | |||||
} | |||||
if (encoding != null && encoding.isFull()) { | |||||
encoding = null; | |||||
} | |||||
if (encoding == null) { | |||||
encoding = new SimpleSingleByteEncoding( | |||||
getFontName() + "EncodingSupp" + (additionalsCount + 1)); | |||||
this.additionalEncodings.add(encoding); | |||||
mappedStart += 256; | |||||
} | |||||
return (char)(mappedStart + encoding.addCharacter(unencoded.getCharacter())); | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public boolean hasChar(char c) { | public boolean hasChar(char c) { | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Indicates whether the encoding has additional encodings besides the primary encoding. | |||||
* @return true if there are additional encodings. | |||||
*/ | |||||
public boolean hasAdditionalEncodings() { | |||||
return (this.additionalEncodings != null) && (this.additionalEncodings.size() > 0); | |||||
} | |||||
/** | |||||
* Returns the number of additional encodings this single-byte font maintains. | |||||
* @return the number of additional encodings | |||||
*/ | |||||
public int getAdditionalEncodingCount() { | |||||
if (hasAdditionalEncodings()) { | |||||
return this.additionalEncodings.size(); | |||||
} else { | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* Returns an additional encoding. | |||||
* @param index the index of the additional encoding | |||||
* @return the additional encoding | |||||
* @throws IndexOutOfBoundsException if the index is out of bounds | |||||
*/ | |||||
public SimpleSingleByteEncoding getAdditionalEncoding(int index) | |||||
throws IndexOutOfBoundsException { | |||||
if (hasAdditionalEncodings()) { | |||||
return this.additionalEncodings.get(index); | |||||
} else { | |||||
throw new IndexOutOfBoundsException("No additional encodings available"); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Returns an array with the widths for an additional encoding. | * Returns an array with the widths for an additional encoding. | ||||
* @param index the index of the additional encoding | * @param index the index of the additional encoding | ||||
return arr; | return arr; | ||||
} | } | ||||
private static final class UnencodedCharacter { | |||||
protected static final class UnencodedCharacter { | |||||
private final NamedCharacter character; | private final NamedCharacter character; | ||||
private final int width; | private final int width; |
return false; | return false; | ||||
} | } | ||||
public boolean isCID() { | |||||
return getFontType() == FontType.TYPE1C; | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public int getMaxAscent(int size) { | public int getMaxAscent(int size) { | ||||
return getAscender(size); | return getAscender(size); |
returnFont.setWeight(otf.getWeightClass()); | returnFont.setWeight(otf.getWeightClass()); | ||||
if (isCid) { | if (isCid) { | ||||
if (otf instanceof OTFFile) { | if (otf instanceof OTFFile) { | ||||
if (((OTFFile) otf).isType1() && embeddingMode == EmbeddingMode.SUBSET) { | |||||
multiFont.setFontType(FontType.TYPE1C); | |||||
copyGlyphMetricsSingleByte(otf); | |||||
} | |||||
multiFont.setCIDType(CIDFontType.CIDTYPE0); | multiFont.setCIDType(CIDFontType.CIDTYPE0); | ||||
} else { | } else { | ||||
multiFont.setCIDType(CIDFontType.CIDTYPE2); | multiFont.setCIDType(CIDFontType.CIDTYPE2); | ||||
private void copyGlyphMetricsSingleByte(OpenFont otf) { | private void copyGlyphMetricsSingleByte(OpenFont otf) { | ||||
int[] wx = otf.getWidths(); | int[] wx = otf.getWidths(); | ||||
Rectangle[] bboxes = otf.getBoundingBoxes(); | Rectangle[] bboxes = otf.getBoundingBoxes(); | ||||
for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) { | |||||
singleFont.setWidth(i, otf.getCharWidth(i)); | |||||
int[] bbox = otf.getBBox(i); | |||||
singleFont.setBoundingBox(i, | |||||
new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1])); | |||||
if (singleFont != null) { | |||||
for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) { | |||||
singleFont.setWidth(i, otf.getCharWidth(i)); | |||||
int[] bbox = otf.getBBox(i); | |||||
singleFont.setBoundingBox(i, | |||||
new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1])); | |||||
} | |||||
} | } | ||||
for (CMapSegment segment : otf.getCMaps()) { | for (CMapSegment segment : otf.getCMaps()) { | ||||
if (segment.getUnicodeStart() < 0xFFFE) { | if (segment.getUnicodeStart() < 0xFFFE) { | ||||
for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) { | for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) { | ||||
int codePoint = singleFont.getEncoding().mapChar(u); | |||||
int codePoint = 0; | |||||
if (singleFont != null) { | |||||
codePoint = singleFont.getEncoding().mapChar(u); | |||||
} | |||||
if (codePoint <= 0) { | if (codePoint <= 0) { | ||||
int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart(); | int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart(); | ||||
String glyphName = otf.getGlyphName(glyphIndex); | String glyphName = otf.getGlyphName(glyphIndex); | ||||
if (glyphName.length() > 0) { | if (glyphName.length() > 0) { | ||||
String unicode = Character.toString(u); | String unicode = Character.toString(u); | ||||
NamedCharacter nc = new NamedCharacter(glyphName, unicode); | NamedCharacter nc = new NamedCharacter(glyphName, unicode); | ||||
singleFont.addUnencodedCharacter(nc, wx[glyphIndex], bboxes[glyphIndex]); | |||||
returnFont.addUnencodedCharacter(nc, wx[glyphIndex], bboxes[glyphIndex]); | |||||
} | } | ||||
} | } | ||||
} | } |
import org.apache.fontbox.cff.CFFDataInput; | import org.apache.fontbox.cff.CFFDataInput; | ||||
import org.apache.fontbox.cff.CFFFont; | import org.apache.fontbox.cff.CFFFont; | ||||
import org.apache.fontbox.cff.CFFParser; | import org.apache.fontbox.cff.CFFParser; | ||||
import org.apache.fontbox.cff.CFFType1Font; | |||||
public class OTFFile extends OpenFont { | public class OTFFile extends OpenFont { | ||||
private static long readLong(CFFDataInput input) throws IOException { | private static long readLong(CFFDataInput input) throws IOException { | ||||
return (input.readCard16() << 16) | input.readCard16(); | return (input.readCard16() << 16) | input.readCard16(); | ||||
} | } | ||||
public boolean isType1() { | |||||
return fileFont instanceof CFFType1Font; | |||||
} | |||||
} | } |
super(); | super(); | ||||
} | } | ||||
public void readFont(FontFileReader in, String embeddedName, String header, | |||||
MultiByteFont mbFont) throws IOException { | |||||
this.mbFont = mbFont; | |||||
readFont(in, embeddedName, header, mbFont.getUsedGlyphs()); | |||||
public void readFont(FontFileReader in, String embeddedName, MultiByteFont mbFont) throws IOException { | |||||
readFont(in, embeddedName, mbFont, mbFont.getUsedGlyphs()); | |||||
} | } | ||||
/** | /** | ||||
* | * | ||||
* @param in FontFileReader to read from | * @param in FontFileReader to read from | ||||
* @param embeddedName Name to be checked for in the font file | * @param embeddedName Name to be checked for in the font file | ||||
* @param header The header of the font file | |||||
* @param usedGlyphs Map of glyphs (glyphs has old index as (Integer) key and | * @param usedGlyphs Map of glyphs (glyphs has old index as (Integer) key and | ||||
* new index as (Integer) value) | * new index as (Integer) value) | ||||
* @throws IOException in case of an I/O problem | * @throws IOException in case of an I/O problem | ||||
*/ | */ | ||||
void readFont(FontFileReader in, String embeddedName, String header, | |||||
void readFont(FontFileReader in, String embeddedName, MultiByteFont mbFont, | |||||
Map<Integer, Integer> usedGlyphs) throws IOException { | Map<Integer, Integer> usedGlyphs) throws IOException { | ||||
this.mbFont = mbFont; | |||||
fontFile = in; | fontFile = in; | ||||
currentPos = 0; | currentPos = 0; | ||||
} else { | } else { | ||||
writeByte(0); | writeByte(0); | ||||
for (int entry : gidToSID.values()) { | for (int entry : gidToSID.values()) { | ||||
if (entry == 0) { | |||||
continue; | |||||
} | |||||
writeCard16(entry); | writeCard16(entry); | ||||
} | } | ||||
} | } |
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import org.apache.fop.fonts.CustomFont; | |||||
import org.apache.fop.fonts.EmbeddingMode; | |||||
import org.apache.fop.fonts.FontType; | |||||
/** | /** | ||||
* PDFStream for embeddable OpenType CFF fonts. | * PDFStream for embeddable OpenType CFF fonts. | ||||
*/ | */ | ||||
public class PDFCFFStreamType0C extends AbstractPDFFontStream { | public class PDFCFFStreamType0C extends AbstractPDFFontStream { | ||||
private byte[] cffData; | private byte[] cffData; | ||||
private boolean fullEmbed; | |||||
private String type; | |||||
/** | /** | ||||
* Main constructor | * Main constructor | ||||
* @param fullEmbed Determines whether the font is fully embedded | |||||
*/ | */ | ||||
public PDFCFFStreamType0C(boolean fullEmbed) { | |||||
public PDFCFFStreamType0C(CustomFont font) { | |||||
super(); | super(); | ||||
this.fullEmbed = fullEmbed; | |||||
if (font.getEmbeddingMode() == EmbeddingMode.FULL) { | |||||
type = "OpenType"; | |||||
} else if (font.getFontType() == FontType.TYPE0) { | |||||
type = "CIDFontType0C"; | |||||
} else { | |||||
type = font.getFontType().getName(); | |||||
} | |||||
} | } | ||||
protected int getSizeHint() throws IOException { | protected int getSizeHint() throws IOException { | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
protected void populateStreamDict(Object lengthEntry) { | protected void populateStreamDict(Object lengthEntry) { | ||||
String type = (fullEmbed) ? "OpenType" : "CIDFontType0C"; | |||||
put("Subtype", new PDFName(type)); | put("Subtype", new PDFName(type)); | ||||
super.populateStreamDict(lengthEntry); | super.populateStreamDict(lengthEntry); | ||||
} | } |
import java.net.URI; | import java.net.URI; | ||||
import java.net.URISyntaxException; | import java.net.URISyntaxException; | ||||
import java.text.DecimalFormat; | import java.text.DecimalFormat; | ||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.BitSet; | import java.util.BitSet; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Iterator; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.SortedSet; | import java.util.SortedSet; | ||||
assert font instanceof PDFFontType0; | assert font instanceof PDFFontType0; | ||||
((PDFFontType0)font).setCMAP(cmap); | ((PDFFontType0)font).setCMAP(cmap); | ||||
((PDFFontType0)font).setDescendantFonts(cidFont); | ((PDFFontType0)font).setDescendantFonts(cidFont); | ||||
} else if (fonttype == FontType.TYPE1C | |||||
&& (metrics instanceof LazyFont || metrics instanceof MultiByteFont)) { | |||||
handleType1CFont(pdfdesc, font, metrics, fontname, basefont, descriptor); | |||||
} else { | } else { | ||||
assert font instanceof PDFFontNonBase14; | assert font instanceof PDFFontNonBase14; | ||||
PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font; | PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font; | ||||
} | } | ||||
} | } | ||||
private void handleType1CFont(PDFFontDescriptor pdfdesc, PDFFont font, FontMetrics metrics, String fontname, | |||||
String basefont, FontDescriptor descriptor) { | |||||
PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font; | |||||
nonBase14.setDescriptor(pdfdesc); | |||||
MultiByteFont singleByteFont; | |||||
if (metrics instanceof LazyFont) { | |||||
singleByteFont = (MultiByteFont)((LazyFont)metrics).getRealFont(); | |||||
} else { | |||||
singleByteFont = (MultiByteFont)metrics; | |||||
} | |||||
Map<Integer, Integer> usedGlyphs = singleByteFont.getUsedGlyphs(); | |||||
SortedSet<Integer> keys = new TreeSet<Integer>(usedGlyphs.keySet()); | |||||
keys.remove(0); | |||||
int count = keys.size(); | |||||
Iterator<String> usedGlyphNames = singleByteFont.getUsedGlyphNames().values().iterator(); | |||||
count = setupFontMetrics(nonBase14, pdfdesc, usedGlyphNames, 0, count, metrics); | |||||
List<PDFFontNonBase14> additionalEncodings = addAdditionalEncodings(metrics, descriptor, fontname, basefont); | |||||
for (int j = 0; j < additionalEncodings.size(); j++) { | |||||
PDFFontNonBase14 additional = additionalEncodings.get(j); | |||||
int start = 256 * (j + 1); | |||||
count = setupFontMetrics(additional, pdfdesc, usedGlyphNames, start, count, metrics); | |||||
} | |||||
} | |||||
private int setupFontMetrics(PDFFontNonBase14 font, PDFFontDescriptor pdfdesc, | |||||
Iterator<String> usedGlyphNames, int start, int count, FontMetrics metrics) { | |||||
font.setDescriptor(pdfdesc); | |||||
PDFArray differences = new PDFArray(); | |||||
int firstChar = 0; | |||||
differences.add(firstChar); | |||||
int lastChar = Math.min(count, 255); | |||||
int[] newWidths = new int[lastChar + 1]; | |||||
for (int i = 0; i < newWidths.length; i++) { | |||||
newWidths[i] = metrics.getWidth(start + i, 1); | |||||
differences.add(new PDFName(usedGlyphNames.next())); | |||||
count--; | |||||
} | |||||
font.setWidthMetrics(firstChar, | |||||
lastChar, | |||||
new PDFArray(null, newWidths)); | |||||
PDFEncoding pdfEncoding = new PDFEncoding("WinAnsiEncoding"); | |||||
getDocument().registerTrailerObject(pdfEncoding); | |||||
pdfEncoding.setDifferences(differences); | |||||
font.setEncoding(pdfEncoding); | |||||
return count; | |||||
} | |||||
private List<PDFFontNonBase14> addAdditionalEncodings(FontMetrics metrics, FontDescriptor descriptor, | |||||
String fontname, String basefont) { | |||||
List<PDFFontNonBase14> additionalEncodings = new ArrayList<PDFFontNonBase14>(); | |||||
FontType fonttype = metrics.getFontType(); | |||||
if (descriptor != null && (fonttype != FontType.TYPE0)) { | |||||
CustomFont singleByteFont; | |||||
if (metrics instanceof LazyFont) { | |||||
singleByteFont = (CustomFont)((LazyFont)metrics).getRealFont(); | |||||
} else { | |||||
singleByteFont = (CustomFont)metrics; | |||||
} | |||||
//Handle additional encodings (characters outside the primary encoding) | |||||
if (singleByteFont.hasAdditionalEncodings()) { | |||||
for (int i = additionalEncodings.size(), | |||||
c = singleByteFont.getAdditionalEncodingCount(); i < c; i++) { | |||||
SimpleSingleByteEncoding addEncoding | |||||
= singleByteFont.getAdditionalEncoding(i); | |||||
String name = fontname + "_" + (i + 1); | |||||
Object pdfenc = createPDFEncoding(addEncoding, singleByteFont.getFontName()); | |||||
PDFFontNonBase14 addFont = (PDFFontNonBase14)PDFFont.createFont( | |||||
name, fonttype, | |||||
basefont, pdfenc); | |||||
getDocument().registerObject(addFont); | |||||
getDocument().getResources().addFont(addFont); | |||||
additionalEncodings.add(addFont); | |||||
} | |||||
} | |||||
} | |||||
return additionalEncodings; | |||||
} | |||||
private void generateToUnicodeCmap(PDFFont font, SingleByteEncoding encoding) { | private void generateToUnicodeCmap(PDFFont font, SingleByteEncoding encoding) { | ||||
PDFCMap cmap = new PDFToUnicodeCMap(encoding.getUnicodeCharMap(), | PDFCMap cmap = new PDFToUnicodeCMap(encoding.getUnicodeCharMap(), | ||||
"fop-ucs-H", | "fop-ucs-H", | ||||
((PDFT1Stream) embeddedFont).setData(pfb); | ((PDFT1Stream) embeddedFont).setData(pfb); | ||||
} | } | ||||
} else if (desc.getFontType() == FontType.TYPE1C) { | } else if (desc.getFontType() == FontType.TYPE1C) { | ||||
byte[] file = IOUtils.toByteArray(in); | |||||
PDFCFFStream embeddedFont2 = new PDFCFFStream("Type1C"); | |||||
embeddedFont2.setData(file); | |||||
return embeddedFont2; | |||||
if (font.getEmbeddingMode() == EmbeddingMode.SUBSET) { | |||||
FontFileReader reader = new FontFileReader(in); | |||||
String header = OFFontLoader.readHeader(reader); | |||||
byte[] fontBytes = getFontSubsetBytes(reader, (MultiByteFont) font, header, fontPrefix, desc, true); | |||||
embeddedFont = getFontStream(font, fontBytes, true); | |||||
} else { | |||||
byte[] file = IOUtils.toByteArray(in); | |||||
PDFCFFStream embeddedFont2 = new PDFCFFStream("Type1C"); | |||||
embeddedFont2.setData(file); | |||||
return embeddedFont2; | |||||
} | |||||
} else if (desc.getFontType() == FontType.CIDTYPE0) { | } else if (desc.getFontType() == FontType.CIDTYPE0) { | ||||
byte[] file = IOUtils.toByteArray(in); | byte[] file = IOUtils.toByteArray(in); | ||||
PDFCFFStream embeddedFont2 = new PDFCFFStream("CIDFontType0C"); | PDFCFFStream embeddedFont2 = new PDFCFFStream("CIDFontType0C"); | ||||
String fontPrefix, FontDescriptor desc, boolean isCFF) throws IOException { | String fontPrefix, FontDescriptor desc, boolean isCFF) throws IOException { | ||||
if (isCFF) { | if (isCFF) { | ||||
OTFSubSetFile otfFile = new OTFSubSetFile(); | OTFSubSetFile otfFile = new OTFSubSetFile(); | ||||
otfFile.readFont(reader, fontPrefix + desc.getEmbedFontName(), header, mbfont); | |||||
otfFile.readFont(reader, fontPrefix + desc.getEmbedFontName(), mbfont); | |||||
return otfFile.getFontSubset(); | return otfFile.getFontSubset(); | ||||
} else { | } else { | ||||
TTFSubSetFile otfFile = new TTFSubSetFile(); | TTFSubSetFile otfFile = new TTFSubSetFile(); | ||||
throws IOException { | throws IOException { | ||||
AbstractPDFStream embeddedFont; | AbstractPDFStream embeddedFont; | ||||
if (isCFF) { | if (isCFF) { | ||||
embeddedFont = new PDFCFFStreamType0C(font.getEmbeddingMode() == EmbeddingMode.FULL); | |||||
embeddedFont = new PDFCFFStreamType0C(font); | |||||
((PDFCFFStreamType0C) embeddedFont).setData(fontBytes, fontBytes.length); | ((PDFCFFStreamType0C) embeddedFont).setData(fontBytes, fontBytes.length); | ||||
} else { | } else { | ||||
embeddedFont = new PDFTTFStream(fontBytes.length); | embeddedFont = new PDFTTFStream(fontBytes.length); |
private String startText; | private String startText; | ||||
private String endText; | private String endText; | ||||
private boolean useMultiByte; | private boolean useMultiByte; | ||||
private boolean useCid; | |||||
private StringBuffer bufTJ; | private StringBuffer bufTJ; | ||||
private int textRenderingMode = TR_FILL; | private int textRenderingMode = TR_FILL; | ||||
PDFNumber.doubleOut(lt[5], DEC, sb); | PDFNumber.doubleOut(lt[5], DEC, sb); | ||||
} | } | ||||
private static void writeChar(char ch, StringBuffer sb, boolean multibyte) { | |||||
private static void writeChar(char ch, StringBuffer sb, boolean multibyte, boolean cid) { | |||||
if (!multibyte) { | if (!multibyte) { | ||||
if (ch < 32 || ch > 127) { | |||||
if (cid || ch < 32 || ch > 127) { | |||||
sb.append("\\").append(Integer.toOctalString(ch)); | sb.append("\\").append(Integer.toOctalString(ch)); | ||||
} else { | } else { | ||||
switch (ch) { | switch (ch) { | ||||
} | } | ||||
private void writeChar(char ch, StringBuffer sb) { | private void writeChar(char ch, StringBuffer sb) { | ||||
writeChar(ch, sb, useMultiByte); | |||||
writeChar(ch, sb, useMultiByte, useCid); | |||||
} | } | ||||
private void checkInTextObject() { | private void checkInTextObject() { | ||||
* @param fontSize the font size (in points) | * @param fontSize the font size (in points) | ||||
* @param multiByte true indicates the font is a multi-byte font, false means single-byte | * @param multiByte true indicates the font is a multi-byte font, false means single-byte | ||||
*/ | */ | ||||
public void updateTf(String fontName, double fontSize, boolean multiByte) { | |||||
public void updateTf(String fontName, double fontSize, boolean multiByte, boolean cid) { | |||||
checkInTextObject(); | checkInTextObject(); | ||||
if (!fontName.equals(this.currentFontName) || (fontSize != this.currentFontSize)) { | if (!fontName.equals(this.currentFontName) || (fontSize != this.currentFontSize)) { | ||||
writeTJ(); | writeTJ(); | ||||
this.currentFontName = fontName; | this.currentFontName = fontName; | ||||
this.currentFontSize = fontSize; | this.currentFontSize = fontSize; | ||||
this.useMultiByte = multiByte; | this.useMultiByte = multiByte; | ||||
this.useCid = cid; | |||||
writeTf(fontName, fontSize); | writeTf(fontName, fontSize); | ||||
} | } | ||||
} | } | ||||
* Writes a "Tj" command with specified character code. | * Writes a "Tj" command with specified character code. | ||||
* @param ch character code to write | * @param ch character code to write | ||||
*/ | */ | ||||
public void writeTj(char ch) { | |||||
public void writeTj(char ch, boolean multibyte, boolean cid) { | |||||
StringBuffer sb = new StringBuffer(); | StringBuffer sb = new StringBuffer(); | ||||
sb.append('<'); | |||||
writeChar(ch, sb, true); | |||||
sb.append('>'); | |||||
sb.append(startText); | |||||
writeChar(ch, sb, multibyte, cid); | |||||
sb.append(endText); | |||||
sb.append(" Tj\n"); | sb.append(" Tj\n"); | ||||
write(sb); | write(sb); | ||||
} | } |
// This assumes that *all* CIDFonts use a /ToUnicode mapping | // This assumes that *all* CIDFonts use a /ToUnicode mapping | ||||
Typeface tf = getTypeface(fontKey); | Typeface tf = getTypeface(fontKey); | ||||
SingleByteFont singleByteFont = null; | |||||
if (tf instanceof SingleByteFont) { | |||||
singleByteFont = (SingleByteFont)tf; | |||||
} | |||||
Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints); | Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints); | ||||
String fontName = font.getFontName(); | String fontName = font.getFontName(); | ||||
PDFTextUtil textutil = generator.getTextUtil(); | PDFTextUtil textutil = generator.getTextUtil(); | ||||
textutil.updateTf(fontKey, fontSize, tf.isMultiByte()); | |||||
textutil.updateTf(fontKey, fontSize, tf.isMultiByte(), tf.isCID()); | |||||
double shear = 0; | double shear = 0; | ||||
boolean simulateStyle = tf instanceof CustomFont && ((CustomFont) tf).getSimulateStyle(); | boolean simulateStyle = tf instanceof CustomFont && ((CustomFont) tf).getSimulateStyle(); | ||||
float glyphAdjust = 0; | float glyphAdjust = 0; | ||||
if (font.hasChar(orgChar)) { | if (font.hasChar(orgChar)) { | ||||
ch = font.mapChar(orgChar); | ch = font.mapChar(orgChar); | ||||
ch = selectAndMapSingleByteFont(singleByteFont, fontName, fontSize, textutil, ch); | |||||
ch = selectAndMapSingleByteFont(tf, fontName, fontSize, textutil, ch); | |||||
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) { | if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) { | ||||
glyphAdjust += wordSpacing; | glyphAdjust += wordSpacing; | ||||
} | } | ||||
glyphAdjust += wordSpacing; | glyphAdjust += wordSpacing; | ||||
} | } | ||||
} | } | ||||
ch = selectAndMapSingleByteFont(singleByteFont, fontName, fontSize, | |||||
textutil, ch); | |||||
ch = selectAndMapSingleByteFont(tf, fontName, fontSize, textutil, ch); | |||||
} | } | ||||
textutil.writeTJMappedChar(ch); | textutil.writeTJMappedChar(ch); | ||||
assert dp != null; | assert dp != null; | ||||
String fk = getFontInfo().getInternalFontKey(triplet); | String fk = getFontInfo().getInternalFontKey(triplet); | ||||
Typeface tf = getTypeface(fk); | Typeface tf = getTypeface(fk); | ||||
if (tf.isMultiByte()) { | |||||
if (tf.isMultiByte() || tf.isCID()) { | |||||
int fs = state.getFontSize(); | int fs = state.getFontSize(); | ||||
float fsPoints = fs / 1000f; | float fsPoints = fs / 1000f; | ||||
Font f = getFontInfo().getFontInstance(triplet, fs); | Font f = getFontInfo().getFontInstance(triplet, fs); | ||||
double yoLast = 0f; | double yoLast = 0f; | ||||
double wox = wordSpacing; | double wox = wordSpacing; | ||||
tu.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f)); | tu.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f)); | ||||
tu.updateTf(fk, fsPoints, true); | |||||
tu.updateTf(fk, fsPoints, tf.isMultiByte(), true); | |||||
generator.updateCharacterSpacing(letterSpacing / 1000f); | generator.updateCharacterSpacing(letterSpacing / 1000f); | ||||
for (int i = 0, n = text.length(); i < n; i++) { | for (int i = 0, n = text.length(); i < n; i++) { | ||||
char ch = text.charAt(i); | char ch = text.charAt(i); | ||||
double xd = (xo - xoLast) / 1000f; | double xd = (xo - xoLast) / 1000f; | ||||
double yd = (yo - yoLast) / 1000f; | double yd = (yo - yoLast) / 1000f; | ||||
tu.writeTd(xd, yd); | tu.writeTd(xd, yd); | ||||
tu.writeTj(f.mapChar(ch)); | |||||
ch = f.mapChar(ch); | |||||
ch = selectAndMapSingleByteFont(tf, f.getFontName(), fsPoints, tu, ch); | |||||
tu.writeTj(ch, tf.isMultiByte(), true); | |||||
xc += xa + pa[2]; | xc += xa + pa[2]; | ||||
yc += ya + pa[3]; | yc += ya + pa[3]; | ||||
xoLast = xo; | xoLast = xo; | ||||
} | } | ||||
*/ | */ | ||||
private char selectAndMapSingleByteFont(SingleByteFont singleByteFont, String fontName, | |||||
float fontSize, PDFTextUtil textutil, char ch) { | |||||
if (singleByteFont != null && singleByteFont.hasAdditionalEncodings()) { | |||||
private char selectAndMapSingleByteFont(Typeface tf, String fontName, float fontSize, PDFTextUtil textutil, | |||||
char ch) { | |||||
if ((tf instanceof SingleByteFont && ((SingleByteFont)tf).hasAdditionalEncodings()) || tf.isCID()) { | |||||
int encoding = ch / 256; | int encoding = ch / 256; | ||||
if (encoding == 0) { | if (encoding == 0) { | ||||
textutil.updateTf(fontName, fontSize, singleByteFont.isMultiByte()); | |||||
textutil.updateTf(fontName, fontSize, tf.isMultiByte(), tf.isCID()); | |||||
} else { | } else { | ||||
textutil.updateTf(fontName + "_" + Integer.toString(encoding), | textutil.updateTf(fontName + "_" + Integer.toString(encoding), | ||||
fontSize, singleByteFont.isMultiByte()); | |||||
fontSize, tf.isMultiByte(), tf.isCID()); | |||||
ch = (char)(ch % 256); | ch = (char)(ch % 256); | ||||
} | } | ||||
} | } |
PSFontResource fontResource = null; | PSFontResource fontResource = null; | ||||
PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName()); | PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName()); | ||||
if (!(fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE | if (!(fontType == FontType.TYPE1 || fontType == FontType.TRUETYPE | ||||
|| fontType == FontType.TYPE0) || !(tf instanceof CustomFont)) { | |||||
|| fontType == FontType.TYPE0 || fontType == FontType.TYPE1C) || !(tf instanceof CustomFont)) { | |||||
gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes); | gen.writeDSCComment(DSCConstants.INCLUDE_RESOURCE, fontRes); | ||||
fontResource = PSFontResource.createFontResource(fontRes); | fontResource = PSFontResource.createFontResource(fontRes); | ||||
return fontResource; | return fontResource; | ||||
if (i > 0) { | if (i > 0) { | ||||
fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName() + "." + i); | fontRes = new PSResource(PSResource.TYPE_FONT, tf.getEmbedFontName() + "." + i); | ||||
} | } | ||||
if (fontType == FontType.TYPE0) { | |||||
if (fontType == FontType.TYPE0 || fontType == FontType.TYPE1C) { | |||||
if (((MultiByteFont) tf).isOTFFile()) { | if (((MultiByteFont) tf).isOTFFile()) { | ||||
checkPostScriptLevel3(gen, eventProducer, "OpenType CFF"); | checkPostScriptLevel3(gen, eventProducer, "OpenType CFF"); | ||||
embedType2CFF(gen, (MultiByteFont) tf, in); | embedType2CFF(gen, (MultiByteFont) tf, in); | ||||
private static void embedType2CFF(PSGenerator gen, | private static void embedType2CFF(PSGenerator gen, | ||||
MultiByteFont font, InputStream fontStream) throws IOException { | MultiByteFont font, InputStream fontStream) throws IOException { | ||||
FontFileReader reader = new FontFileReader(fontStream); | FontFileReader reader = new FontFileReader(fontStream); | ||||
String header = OFFontLoader.readHeader(reader); | |||||
String psName; | String psName; | ||||
CFFDataReader cffReader = new CFFDataReader(reader); | CFFDataReader cffReader = new CFFDataReader(reader); | ||||
if (cffReader.getFDSelect() != null) { | if (cffReader.getFDSelect() != null) { | ||||
} else { | } else { | ||||
psName = font.getEmbedFontName(); | psName = font.getEmbedFontName(); | ||||
OTFSubSetFile otfFile = new OTFSubSetFile(); | OTFSubSetFile otfFile = new OTFSubSetFile(); | ||||
otfFile.readFont(reader, psName, header, font); | |||||
otfFile.readFont(reader, psName, font); | |||||
bytes = otfFile.getFontSubset(); | bytes = otfFile.getFontSubset(); | ||||
} | } | ||||
import org.apache.xmlgraphics.ps.PSGenerator; | import org.apache.xmlgraphics.ps.PSGenerator; | ||||
import org.apache.xmlgraphics.ps.PSResource; | import org.apache.xmlgraphics.ps.PSResource; | ||||
import org.apache.fop.fonts.EmbeddingMode; | |||||
import org.apache.fop.fonts.Font; | import org.apache.fop.fonts.Font; | ||||
import org.apache.fop.fonts.FontTriplet; | import org.apache.fop.fonts.FontTriplet; | ||||
import org.apache.fop.fonts.LazyFont; | import org.apache.fop.fonts.LazyFont; | ||||
if (!multiByte || isOTF) { | if (!multiByte || isOTF) { | ||||
char codepoint = (char)(ch % 256); | char codepoint = (char)(ch % 256); | ||||
if (isOTF) { | if (isOTF) { | ||||
codepoint -= (((MultiByteFont)tf).getEmbeddingMode() == EmbeddingMode.FULL) ? 0 : 1; | |||||
accText.append(HexEncoder.encode(codepoint, 2)); | accText.append(HexEncoder.encode(codepoint, 2)); | ||||
} else { | } else { | ||||
PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text | PSGenerator.escapeChar(codepoint, accText); //add character to accumulated text |
double xoLast = 0f; | double xoLast = 0f; | ||||
double yoLast = 0f; | double yoLast = 0f; | ||||
textUtil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, initialPos.getX(), initialPos.getY())); | textUtil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, initialPos.getX(), initialPos.getY())); | ||||
textUtil.updateTf(fk, fsPoints, true); | |||||
textUtil.updateTf(fk, fsPoints, true, false); | |||||
int[][] dp = gv.getGlyphPositionAdjustments(); | int[][] dp = gv.getGlyphPositionAdjustments(); | ||||
for (int i = 0, n = gv.getNumGlyphs(); i < n; i++) { | for (int i = 0, n = gv.getNumGlyphs(); i < n; i++) { | ||||
int gc = gv.getGlyphCode(i); | int gc = gv.getGlyphCode(i); | ||||
double xd = (xo - xoLast) / 1000f; | double xd = (xo - xoLast) / 1000f; | ||||
double yd = (yo - yoLast) / 1000f; | double yd = (yo - yoLast) / 1000f; | ||||
textUtil.writeTd(xd, yd); | textUtil.writeTd(xd, yd); | ||||
textUtil.writeTj((char) gc); | |||||
textUtil.writeTj((char) gc, true, false); | |||||
xc += xa + pa[2]; | xc += xa + pa[2]; | ||||
yc += ya + pa[3]; | yc += ya + pa[3]; | ||||
xoLast = xo; | xoLast = xo; |
return f.isMultiByte(); | return f.isMultiByte(); | ||||
} | } | ||||
protected boolean isCIDFont(String name) { | |||||
Typeface f = fontInfo.getFonts().get(name); | |||||
return f.isCID(); | |||||
} | |||||
/** | /** | ||||
* Writes a "Tf" command, setting a new current font. | * Writes a "Tf" command, setting a new current font. | ||||
* @param f the font to select | * @param f the font to select | ||||
String fontName = f.getFontName(); | String fontName = f.getFontName(); | ||||
float fontSize = (float)f.getFontSize() / 1000f; | float fontSize = (float)f.getFontSize() / 1000f; | ||||
boolean isMultiByte = isMultiByteFont(fontName); | boolean isMultiByte = isMultiByteFont(fontName); | ||||
boolean isCid = isCIDFont(fontName); | |||||
if (!isMultiByte && encoding != 0) { | if (!isMultiByte && encoding != 0) { | ||||
updateTf(fontName + "_" + Integer.toString(encoding), fontSize, isMultiByte); | |||||
updateTf(fontName + "_" + Integer.toString(encoding), fontSize, isMultiByte, isCid); | |||||
} else { | } else { | ||||
updateTf(fontName, fontSize, isMultiByte); | |||||
updateTf(fontName, fontSize, isMultiByte, isCid); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
sourceSansSubset = new OTFSubSetFile(); | sourceSansSubset = new OTFSubSetFile(); | ||||
String sourceSansHeader = OFFontLoader.readHeader(sourceSansReader); | |||||
sourceSansSubset.readFont(sourceSansReader, "SourceSansProBold", sourceSansHeader, glyphs); | |||||
sourceSansSubset.readFont(sourceSansReader, "SourceSansProBold", null, glyphs); | |||||
byte[] sourceSansData = sourceSansSubset.getFontSubset(); | byte[] sourceSansData = sourceSansSubset.getFontSubset(); | ||||
cffReaderSourceSans = new CFFDataReader(sourceSansData); | cffReaderSourceSans = new CFFDataReader(sourceSansData); | ||||
} | } | ||||
private byte[] getSubset(final int opLen) throws IOException { | private byte[] getSubset(final int opLen) throws IOException { | ||||
FontFileReader reader = sourceSansReader; | FontFileReader reader = sourceSansReader; | ||||
String header = OFFontLoader.readHeader(reader); | |||||
OTFSubSetFile otfSubSetFile = new MyOTFSubSetFile(opLen); | OTFSubSetFile otfSubSetFile = new MyOTFSubSetFile(opLen); | ||||
otfSubSetFile.readFont(reader, "StandardOpenType", header, new HashMap<Integer, Integer>()); | |||||
otfSubSetFile.readFont(reader, "StandardOpenType", null, new HashMap<Integer, Integer>()); | |||||
return otfSubSetFile.getFontSubset(); | return otfSubSetFile.getFontSubset(); | ||||
} | } | ||||
package org.apache.fop.pdf; | package org.apache.fop.pdf; | ||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | |||||
import java.net.URI; | import java.net.URI; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
import static org.junit.Assert.assertTrue; | |||||
import org.apache.xmlgraphics.io.ResourceResolver; | import org.apache.xmlgraphics.io.ResourceResolver; | ||||
import org.apache.fop.apps.io.ResourceResolverFactory; | import org.apache.fop.apps.io.ResourceResolverFactory; | ||||
import org.apache.fop.fonts.CIDSet; | import org.apache.fop.fonts.CIDSet; | ||||
import org.apache.fop.fonts.CIDSubset; | import org.apache.fop.fonts.CIDSubset; | ||||
import org.apache.fop.fonts.CustomFont; | |||||
import org.apache.fop.fonts.EmbeddingMode; | import org.apache.fop.fonts.EmbeddingMode; | ||||
import org.apache.fop.fonts.FontUris; | |||||
import org.apache.fop.fonts.MultiByteFont; | import org.apache.fop.fonts.MultiByteFont; | ||||
import org.apache.fop.fonts.truetype.OFFontLoader; | |||||
/** | /** | ||||
* Test case for {@link PDFFactory}. | * Test case for {@link PDFFactory}. | ||||
PDFFont pdfArial = pdfFactory.makeFont("Arial", "Arial", "TTF", font, font); | PDFFont pdfArial = pdfFactory.makeFont("Arial", "Arial", "TTF", font, font); | ||||
assertEquals("/EAAAAB+Arial", pdfArial.getBaseFont().toString()); | assertEquals("/EAAAAB+Arial", pdfArial.getBaseFont().toString()); | ||||
} | } | ||||
@Test | |||||
public void testMakeOTFFont() throws IOException { | |||||
InternalResourceResolver rr = | |||||
ResourceResolverFactory.createDefaultInternalResourceResolver(new File(".").toURI()); | |||||
PDFDocument doc = new PDFDocument(""); | |||||
PDFFactory pdfFactory = new PDFFactory(doc); | |||||
URI uri = new File("test/resources/fonts/otf/SourceSansProBold.otf").toURI(); | |||||
CustomFont sb = OFFontLoader.loadFont(new FontUris(uri, null), | |||||
null, true, EmbeddingMode.SUBSET, null, false, false, rr, false, false); | |||||
for (char c = 0; c < 512; c++) { | |||||
sb.mapChar(c); | |||||
} | |||||
pdfFactory.makeFont("a", "a", "WinAnsiEncoding", sb, sb); | |||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||||
doc.outputTrailer(bos); | |||||
assertEquals(pdfFactory.getDocument().getFontMap().size(), 2); | |||||
PDFFont pdfFont = pdfFactory.getDocument().getFontMap().get("a_1"); | |||||
PDFEncoding enc = (PDFEncoding) pdfFont.get("Encoding"); | |||||
PDFArray diff = (PDFArray) enc.get("Differences"); | |||||
assertEquals(diff.length(), 80); | |||||
assertEquals(diff.get(1).toString(), "/nacute"); | |||||
pdfFont = pdfFactory.getDocument().getFontMap().get("a"); | |||||
enc = (PDFEncoding) pdfFont.get("Encoding"); | |||||
diff = (PDFArray) enc.get("Differences"); | |||||
assertEquals(diff.length(), 257); | |||||
assertEquals(diff.get(2).toString(), "/space"); | |||||
assertTrue(bos.toString().contains("/Subtype /Type1\n")); | |||||
assertTrue(bos.toString().contains("/Subtype /Type1C")); | |||||
} | |||||
} | } |
+ "<00000000000000000000> t\n" | + "<00000000000000000000> t\n" | ||||
+ "/OTFFont.0 0.01 F\n" | + "/OTFFont.0 0.01 F\n" | ||||
+ "1 0 0 -1 0 0 Tm\n" | + "1 0 0 -1 0 0 Tm\n" | ||||
+ "<FFFFFFFFFF> t\n" | |||||
+ "<0000000000> t\n" | |||||
+ "1 0 0 -1 0 0 Tm\n" | + "1 0 0 -1 0 0 Tm\n" | ||||
+ "<FFFFFFFFFF> t\n" | |||||
+ "<0000000000> t\n" | |||||
+ "/TTFFont 0.01 F\n" | + "/TTFFont 0.01 F\n" | ||||
+ "1 0 0 -1 0 0 Tm\n" | + "1 0 0 -1 0 0 Tm\n" | ||||
+ "<00000000000000000000> t\n")); | + "<00000000000000000000> t\n")); |
<include name="org/apache/fop/util/CharUtilities.class"/> | <include name="org/apache/fop/util/CharUtilities.class"/> | ||||
<include name="org/apache/fop/util/DecimalFormatCache*.class"/> | <include name="org/apache/fop/util/DecimalFormatCache*.class"/> | ||||
<include name="org/apache/fop/util/ImageObject.class"/> | <include name="org/apache/fop/util/ImageObject.class"/> | ||||
<include name="org/apache/fop/util/HexEncoder.class"/> | |||||
</patternset> | </patternset> | ||||
<!-- PDF transcoder --> | <!-- PDF transcoder --> | ||||
<patternset> | <patternset> |