git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_FontMerging@1600606 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
<Method name="hasValueOfElementName"/> | <Method name="hasValueOfElementName"/> | ||||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/> | <Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/> | ||||
</Match> | </Match> | ||||
<Match> | |||||
<Class name="org.apache.fop.pdf.PDFCFFStream"/> | |||||
<Or> | |||||
<Bug pattern="EI_EXPOSE_REP"/> | |||||
<Bug pattern="EI_EXPOSE_REP2"/> | |||||
</Or> | |||||
</Match> | |||||
</FindBugsFilter> | </FindBugsFilter> |
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.net.URI; | import java.net.URI; | ||||
import java.util.ArrayList; | |||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.List; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
private Map<Integer, Map<Integer, Integer>> kerning; | private Map<Integer, Map<Integer, Integer>> kerning; | ||||
private boolean useKerning = true; | private boolean useKerning = true; | ||||
/** the character map, mapping Unicode ranges to glyph indices. */ | |||||
protected List<CMapSegment> cmap = new ArrayList<CMapSegment>(); | |||||
private boolean useAdvanced = true; | private boolean useAdvanced = true; | ||||
/** | /** | ||||
public CustomFont(InternalResourceResolver resourceResolver) { | public CustomFont(InternalResourceResolver resourceResolver) { | ||||
this.resourceResolver = resourceResolver; | this.resourceResolver = resourceResolver; | ||||
} | } | ||||
/** the character map, mapping Unicode ranges to glyph indices. */ | |||||
protected CMapSegment[] cmap; | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public String getFontName() { | public String getFontName() { | ||||
* @param cmap the character map | * @param cmap the character map | ||||
*/ | */ | ||||
public void setCMap(CMapSegment[] cmap) { | public void setCMap(CMapSegment[] cmap) { | ||||
this.cmap = new CMapSegment[cmap.length]; | |||||
System.arraycopy(cmap, 0, this.cmap, 0, cmap.length); | |||||
this.cmap.clear(); | |||||
for (CMapSegment c : cmap) { | |||||
this.cmap.add(c); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
* @return the character map | * @return the character map | ||||
*/ | */ | ||||
public CMapSegment[] getCMap() { | public CMapSegment[] getCMap() { | ||||
CMapSegment[] copy = new CMapSegment[cmap.length]; | |||||
System.arraycopy(this.cmap, 0, copy, 0, this.cmap.length); | |||||
return copy; | |||||
return cmap.toArray(new CMapSegment[cmap.size()]); | |||||
} | } | ||||
public int getUnderlinePosition(int size) { | public int getUnderlinePosition(int size) { |
*/ | */ | ||||
public static final FontType TRUETYPE = new FontType("TrueType", 5); | public static final FontType TRUETYPE = new FontType("TrueType", 5); | ||||
public static final FontType TYPE1C = new FontType("Type1C", 6); | |||||
public static final FontType CIDTYPE0 = new FontType("CIDFontType0", 7); | |||||
private final String name; | private final String name; | ||||
private final int value; | private final int value; | ||||
package org.apache.fop.fonts; | package org.apache.fop.fonts; | ||||
import java.awt.Rectangle; | import java.awt.Rectangle; | ||||
import java.io.InputStream; | |||||
import java.nio.CharBuffer; | import java.nio.CharBuffer; | ||||
import java.nio.IntBuffer; | import java.nio.IntBuffer; | ||||
import java.util.BitSet; | import java.util.BitSet; | ||||
private int defaultWidth; | private int defaultWidth; | ||||
private CIDFontType cidType = CIDFontType.CIDTYPE2; | private CIDFontType cidType = CIDFontType.CIDTYPE2; | ||||
private final CIDSet cidSet; | |||||
protected final CIDSet cidSet; | |||||
/* advanced typographic support */ | /* advanced typographic support */ | ||||
private GlyphDefinitionTable gdef; | private GlyphDefinitionTable gdef; | ||||
if (idx < NUM_MOST_LIKELY_GLYPHS && mostLikelyGlyphs[idx] != 0) { | if (idx < NUM_MOST_LIKELY_GLYPHS && mostLikelyGlyphs[idx] != 0) { | ||||
return mostLikelyGlyphs[idx]; | return mostLikelyGlyphs[idx]; | ||||
} | } | ||||
for (int i = 0; (i < cmap.length) && retIdx == 0; i++) { | |||||
if (cmap[i].getUnicodeStart() <= idx | |||||
&& cmap[i].getUnicodeEnd() >= idx) { | |||||
retIdx = cmap[i].getGlyphStartIndex() | |||||
for (CMapSegment i : cmap) { | |||||
if (retIdx == 0 | |||||
&& i.getUnicodeStart() <= idx | |||||
&& i.getUnicodeEnd() >= idx) { | |||||
retIdx = i.getGlyphStartIndex() | |||||
+ idx | + idx | ||||
- cmap[i].getUnicodeStart(); | |||||
- i.getUnicodeStart(); | |||||
if (idx < NUM_MOST_LIKELY_GLYPHS) { | if (idx < NUM_MOST_LIKELY_GLYPHS) { | ||||
mostLikelyGlyphs[idx] = retIdx; | mostLikelyGlyphs[idx] = retIdx; | ||||
} | } | ||||
* Add a private use mapping {PU,GI} to the existing character map. | * Add a private use mapping {PU,GI} to the existing character map. | ||||
* N.B. Does not insert in order, merely appends to end of existing map. | * N.B. Does not insert in order, merely appends to end of existing map. | ||||
*/ | */ | ||||
private synchronized void addPrivateUseMapping(int pu, int gi) { | |||||
protected synchronized void addPrivateUseMapping(int pu, int gi) { | |||||
assert findGlyphIndex(pu) == SingleByteEncoding.NOT_FOUND_CODE_POINT; | assert findGlyphIndex(pu) == SingleByteEncoding.NOT_FOUND_CODE_POINT; | ||||
CMapSegment[] oldCmap = cmap; | |||||
int cmapLength = oldCmap.length; | |||||
CMapSegment[] newCmap = new CMapSegment [ cmapLength + 1 ]; | |||||
System.arraycopy(oldCmap, 0, newCmap, 0, cmapLength); | |||||
newCmap [ cmapLength ] = new CMapSegment(pu, pu, gi); | |||||
cmap = newCmap; | |||||
cmap.add(new CMapSegment(pu, pu, gi)); | |||||
} | } | ||||
/** | /** | ||||
// [TBD] - needs optimization, i.e., change from linear search to binary search | // [TBD] - needs optimization, i.e., change from linear search to binary search | ||||
private int findCharacterFromGlyphIndex(int gi, boolean augment) { | private int findCharacterFromGlyphIndex(int gi, boolean augment) { | ||||
int cc = 0; | int cc = 0; | ||||
for (int i = 0, n = cmap.length; i < n; i++) { | |||||
CMapSegment segment = cmap [ i ]; | |||||
for (CMapSegment segment : cmap) { | |||||
int s = segment.getGlyphStartIndex(); | int s = segment.getGlyphStartIndex(); | ||||
int e = s + (segment.getUnicodeEnd() - segment.getUnicodeStart()); | int e = s + (segment.getUnicodeEnd() - segment.getUnicodeStart()); | ||||
if ((gi >= s) && (gi <= e)) { | if ((gi >= s) && (gi <= e)) { | ||||
bitset.set(0); | bitset.set(0); | ||||
bitset.set(1); | bitset.set(1); | ||||
bitset.set(2); | bitset.set(2); | ||||
for (int i = 0; i < cmap.length; i++) { | |||||
int start = cmap[i].getUnicodeStart(); | |||||
int end = cmap[i].getUnicodeEnd(); | |||||
int glyphIndex = cmap[i].getGlyphStartIndex(); | |||||
for (CMapSegment i : cmap) { | |||||
int start = i.getUnicodeStart(); | |||||
int end = i.getUnicodeEnd(); | |||||
int glyphIndex = i.getGlyphStartIndex(); | |||||
while (start++ < end + 1) { | while (start++ < end + 1) { | ||||
bitset.set(glyphIndex++); | bitset.set(glyphIndex++); | ||||
} | } | ||||
protected char[] getChars() { | protected char[] getChars() { | ||||
// the width array is set when the font is built | // the width array is set when the font is built | ||||
char[] chars = new char[width.length]; | char[] chars = new char[width.length]; | ||||
for (int i = 0; i < cmap.length; i++) { | |||||
int start = cmap[i].getUnicodeStart(); | |||||
int end = cmap[i].getUnicodeEnd(); | |||||
int glyphIndex = cmap[i].getGlyphStartIndex(); | |||||
for (CMapSegment i : cmap) { | |||||
int start = i.getUnicodeStart(); | |||||
int end = i.getUnicodeEnd(); | |||||
int glyphIndex = i.getGlyphStartIndex(); | |||||
while (start < end + 1) { | while (start < end + 1) { | ||||
chars[glyphIndex++] = (char) start++; | chars[glyphIndex++] = (char) start++; | ||||
} | } | ||||
return cb; | return cb; | ||||
} | } | ||||
public Map<Integer, Integer> getWidthsMap() { | |||||
return null; | |||||
} | |||||
public InputStream getCmapStream() { | |||||
return null; | |||||
} | |||||
} | } | ||||
/** logger */ | /** logger */ | ||||
private static Log log = LogFactory.getLog(SingleByteFont.class); | private static Log log = LogFactory.getLog(SingleByteFont.class); | ||||
private SingleByteEncoding mapping; | |||||
protected SingleByteEncoding mapping; | |||||
private boolean useNativeEncoding = false; | private boolean useNativeEncoding = false; | ||||
private int[] width = null; | |||||
protected int[] width = null; | |||||
private Rectangle[] boundingBoxes; | private Rectangle[] boundingBoxes; | ||||
LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData); | LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData); | ||||
newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i)); | newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i)); | ||||
DICTEntry fontFDEntry = fdEntries.get("FontName"); | DICTEntry fontFDEntry = fdEntries.get("FontName"); | ||||
newFontDict.setFontName(getString(fontFDEntry.getOperands().get(0).intValue())); | |||||
if (fontFDEntry != null) { | |||||
newFontDict.setFontName(getString(fontFDEntry.getOperands().get(0).intValue())); | |||||
} | |||||
DICTEntry privateFDEntry = fdEntries.get("Private"); | DICTEntry privateFDEntry = fdEntries.get("Private"); | ||||
if (privateFDEntry != null) { | if (privateFDEntry != null) { | ||||
newFontDict = setFDData(privateFDEntry, newFontDict); | newFontDict = setFDData(privateFDEntry, newFontDict); |
private final Set<Long> remappedComposites; | private final Set<Long> remappedComposites; | ||||
private final Map<Integer, Integer> subset; | |||||
protected final Map<Integer, Integer> subset; | |||||
private final FontFileReader in; | private final FontFileReader in; | ||||
private Set<Integer> compositeGlyphs = new TreeSet<Integer>(); | private Set<Integer> compositeGlyphs = new TreeSet<Integer>(); | ||||
/** All the glyphs that are composed, but do not appear in the subset. */ | /** All the glyphs that are composed, but do not appear in the subset. */ | ||||
private Set<Integer> composedGlyphs = new TreeSet<Integer>(); | |||||
protected Set<Integer> composedGlyphs = new TreeSet<Integer>(); | |||||
GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry, | |||||
Map<Integer, Integer> glyphs) throws IOException { | |||||
protected GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry, | |||||
Map<Integer, Integer> glyphs) throws IOException { | |||||
mtxTab = metrics; | mtxTab = metrics; | ||||
tableOffset = dirTableEntry.getOffset(); | tableOffset = dirTableEntry.getOffset(); | ||||
remappedComposites = new HashSet<Long>(); | remappedComposites = new HashSet<Long>(); | ||||
* | * | ||||
* @throws IOException an I/O error | * @throws IOException an I/O error | ||||
*/ | */ | ||||
void populateGlyphsWithComposites() throws IOException { | |||||
protected void populateGlyphsWithComposites() throws IOException { | |||||
for (int indexInOriginal : subset.keySet()) { | for (int indexInOriginal : subset.keySet()) { | ||||
scanGlyphsRecursively(indexInOriginal); | scanGlyphsRecursively(indexInOriginal); | ||||
} | } | ||||
* Adds to the subset, all the glyphs that are composed by a glyph, but do not appear themselves | * Adds to the subset, all the glyphs that are composed by a glyph, but do not appear themselves | ||||
* in the subset. | * in the subset. | ||||
*/ | */ | ||||
private void addAllComposedGlyphsToSubset() { | |||||
protected void addAllComposedGlyphsToSubset() { | |||||
int newIndex = subset.size(); | int newIndex = subset.size(); | ||||
for (int composedGlyph : composedGlyphs) { | for (int composedGlyph : composedGlyphs) { | ||||
subset.put(composedGlyph, newIndex++); | subset.put(composedGlyph, newIndex++); |
/** | /** | ||||
* This class represents a TrueType Mtx Entry. | * This class represents a TrueType Mtx Entry. | ||||
*/ | */ | ||||
class OFMtxEntry { | |||||
public class OFMtxEntry { | |||||
private int wx; | private int wx; | ||||
private int lsb; | private int lsb; |
* @return The byte data found in the CFF table | * @return The byte data found in the CFF table | ||||
*/ | */ | ||||
public static byte[] getCFFData(FontFileReader fontFile) throws IOException { | public static byte[] getCFFData(FontFileReader fontFile) throws IOException { | ||||
byte[] cff = new byte[0]; | |||||
byte[] cff = fontFile.getAllBytes(); | |||||
CFFDataInput input = new CFFDataInput(fontFile.getAllBytes()); | CFFDataInput input = new CFFDataInput(fontFile.getAllBytes()); | ||||
input.readBytes(4); //OTTO | input.readBytes(4); //OTTO | ||||
short numTables = input.readShort(); | short numTables = input.readShort(); |
*/ | */ | ||||
public class OTFSubSetFile extends OTFFile { | public class OTFSubSetFile extends OTFFile { | ||||
private byte[] output; | |||||
private int currentPos = 0; | |||||
protected byte[] output; | |||||
protected int currentPos = 0; | |||||
private int realSize = 0; | private int realSize = 0; | ||||
/** A map containing each glyph to be included in the subset | /** A map containing each glyph to be included in the subset | ||||
* with their existing and new GID's **/ | * with their existing and new GID's **/ | ||||
private LinkedHashMap<Integer, Integer> subsetGlyphs; | |||||
protected LinkedHashMap<Integer, Integer> subsetGlyphs = new LinkedHashMap<Integer, Integer>(); | |||||
/** A map of the new GID to SID used to construct the charset table **/ | /** A map of the new GID to SID used to construct the charset table **/ | ||||
private LinkedHashMap<Integer, Integer> gidToSID; | |||||
protected LinkedHashMap<Integer, Integer> gidToSID; | |||||
private CFFIndexData localIndexSubr; | |||||
private CFFIndexData globalIndexSubr; | |||||
protected CFFIndexData localIndexSubr; | |||||
protected CFFIndexData globalIndexSubr; | |||||
/** List of subroutines to write to the local / global indexes in the subset font **/ | /** List of subroutines to write to the local / global indexes in the subset font **/ | ||||
private List<byte[]> subsetLocalIndexSubr; | |||||
private List<byte[]> subsetGlobalIndexSubr; | |||||
protected List<byte[]> subsetLocalIndexSubr; | |||||
protected List<byte[]> subsetGlobalIndexSubr; | |||||
/** For fonts which have an FDSelect or ROS flag in Top Dict, this is used to store the | /** For fonts which have an FDSelect or ROS flag in Top Dict, this is used to store the | ||||
* local subroutine indexes for each group as opposed to the above subsetLocalIndexSubr */ | * local subroutine indexes for each group as opposed to the above subsetLocalIndexSubr */ | ||||
private LinkedHashMap<Integer, FDIndexReference> subsetFDSelect; | private LinkedHashMap<Integer, FDIndexReference> subsetFDSelect; | ||||
/** A list of unique subroutines from the global / local subroutine indexes */ | /** A list of unique subroutines from the global / local subroutine indexes */ | ||||
private List<Integer> localUniques; | |||||
private List<Integer> globalUniques; | |||||
protected List<Integer> localUniques; | |||||
protected List<Integer> globalUniques; | |||||
/** A store of the number of subroutines each global / local subroutine will store **/ | /** A store of the number of subroutines each global / local subroutine will store **/ | ||||
private int subsetLocalSubrCount; | |||||
private int subsetGlobalSubrCount; | |||||
protected int subsetLocalSubrCount; | |||||
protected int subsetGlobalSubrCount; | |||||
/** A list of char string data for each glyph to be stored in the subset font **/ | /** A list of char string data for each glyph to be stored in the subset font **/ | ||||
private List<byte[]> subsetCharStringsIndex; | |||||
protected List<byte[]> subsetCharStringsIndex; | |||||
/** The embedded name to change in the name table **/ | /** The embedded name to change in the name table **/ | ||||
private String embeddedName; | |||||
protected String embeddedName; | |||||
/** An array used to hold the string index data for the subset font **/ | /** An array used to hold the string index data for the subset font **/ | ||||
private List<byte[]> stringIndexData = new ArrayList<byte[]>(); | |||||
protected List<byte[]> stringIndexData = new ArrayList<byte[]>(); | |||||
/** The CFF reader object used to read data and offsets from the original font file */ | /** The CFF reader object used to read data and offsets from the original font file */ | ||||
private CFFDataReader cffReader = null; | |||||
protected CFFDataReader cffReader = null; | |||||
/** The class used to represent this font **/ | /** The class used to represent this font **/ | ||||
private MultiByteFont mbFont; | private MultiByteFont mbFont; | ||||
/** The number of standard strings in CFF **/ | /** The number of standard strings in CFF **/ | ||||
private static final int NUM_STANDARD_STRINGS = 391; | |||||
public static final int NUM_STANDARD_STRINGS = 391; | |||||
/** The operator used to identify a local subroutine reference */ | /** The operator used to identify a local subroutine reference */ | ||||
private static final int LOCAL_SUBROUTINE = 10; | private static final int LOCAL_SUBROUTINE = 10; | ||||
/** The operator used to identify a global subroutine reference */ | /** The operator used to identify a global subroutine reference */ | ||||
return result; | return result; | ||||
} | } | ||||
private void createCFF() throws IOException { | |||||
protected void createCFF() throws IOException { | |||||
//Header | //Header | ||||
writeBytes(cffReader.getHeader()); | writeBytes(cffReader.getHeader()); | ||||
} | } | ||||
} | } | ||||
private List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException { | |||||
protected List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException { | |||||
ArrayList<Integer> fontNameSIDs = new ArrayList<Integer>(); | ArrayList<Integer> fontNameSIDs = new ArrayList<Integer>(); | ||||
List<FontDict> fdFonts = cffReader.getFDFonts(); | List<FontDict> fdFonts = cffReader.getFDFonts(); | ||||
for (int i = 0; i < uniqueNewRefs.size(); i++) { | for (int i = 0; i < uniqueNewRefs.size(); i++) { | ||||
return fontNameSIDs; | return fontNameSIDs; | ||||
} | } | ||||
private void writeBytes(byte[] out) { | |||||
protected void writeBytes(byte[] out) { | |||||
for (int i = 0; i < out.length; i++) { | for (int i = 0; i < out.length; i++) { | ||||
output[currentPos++] = out[i]; | |||||
realSize++; | |||||
writeByte(out[i]); | |||||
} | } | ||||
} | } | ||||
private void writeBytes(byte[] out, int offset, int length) { | |||||
protected void writeBytes(byte[] out, int offset, int length) { | |||||
for (int i = offset; i < offset + length; i++) { | for (int i = offset; i < offset + length; i++) { | ||||
output[currentPos++] = out[i]; | output[currentPos++] = out[i]; | ||||
realSize++; | realSize++; | ||||
} | } | ||||
} | } | ||||
private void writeTopDICT() throws IOException { | |||||
protected void writeTopDICT() throws IOException { | |||||
LinkedHashMap<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); | LinkedHashMap<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); | ||||
List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright", | List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright", | ||||
"FullName", "FamilyName", "Weight", "PostScript"); | "FullName", "FamilyName", "Weight", "PostScript"); | ||||
writeBytes(cidEntryByteData); | writeBytes(cidEntryByteData); | ||||
} | } | ||||
private void writeCIDCount(DICTEntry dictEntry) throws IOException { | |||||
protected void writeCIDCount(DICTEntry dictEntry) throws IOException { | |||||
byte[] cidCountByteData = dictEntry.getByteData(); | byte[] cidCountByteData = dictEntry.getByteData(); | ||||
cidCountByteData = updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0), | cidCountByteData = updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0), | ||||
subsetGlyphs.size()); | subsetGlyphs.size()); | ||||
writeIndex(stringIndexData); | writeIndex(stringIndexData); | ||||
} | } | ||||
private void createCharStringDataCID() throws IOException { | |||||
protected void createCharStringDataCID() throws IOException { | |||||
CFFIndexData charStringsIndex = cffReader.getCharStringIndex(); | CFFIndexData charStringsIndex = cffReader.getCharStringIndex(); | ||||
FDSelect fontDictionary = cffReader.getFDSelect(); | FDSelect fontDictionary = cffReader.getFDSelect(); | ||||
localUniques = foundLocalUniquesB.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); | localUniques = foundLocalUniquesB.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); | ||||
byte[] data = charStringsIndex.getValue(gid); | byte[] data = charStringsIndex.getValue(gid); | ||||
subsetLocalIndexSubr = fdSubrs.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); | subsetLocalIndexSubr = fdSubrs.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); | ||||
subsetLocalSubrCount = foundLocalUniques.get( | |||||
subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()).size(); | |||||
subsetLocalSubrCount = foundLocalUniques.get(subsetFDSelect.get(subsetGlyphs.get(gid)) | |||||
.getNewFDIndex()).size(); | |||||
data = readCharStringData(data, subsetLocalSubrCount); | data = readCharStringData(data, subsetLocalSubrCount); | ||||
subsetCharStringsIndex.add(data); | subsetCharStringsIndex.add(data); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private void writeFDSelect() { | |||||
protected void writeFDSelect() { | |||||
writeByte(0); //Format | writeByte(0); //Format | ||||
for (Integer gid : subsetFDSelect.keySet()) { | for (Integer gid : subsetFDSelect.keySet()) { | ||||
writeByte(subsetFDSelect.get(gid).getNewFDIndex()); | writeByte(subsetFDSelect.get(gid).getNewFDIndex()); | ||||
} | } | ||||
} | } | ||||
private List<Integer> getUsedFDFonts() { | |||||
protected List<Integer> getUsedFDFonts() { | |||||
List<Integer> uniqueNewRefs = new ArrayList<Integer>(); | List<Integer> uniqueNewRefs = new ArrayList<Integer>(); | ||||
for (int gid : subsetFDSelect.keySet()) { | for (int gid : subsetFDSelect.keySet()) { | ||||
int fdIndex = subsetFDSelect.get(gid).getOldFDIndex(); | int fdIndex = subsetFDSelect.get(gid).getOldFDIndex(); | ||||
return uniqueNewRefs; | return uniqueNewRefs; | ||||
} | } | ||||
private List<Integer> writeCIDDictsAndSubrs(List<Integer> uniqueNewRefs) | |||||
protected List<Integer> writeCIDDictsAndSubrs(List<Integer> uniqueNewRefs) | |||||
throws IOException { | throws IOException { | ||||
List<Integer> privateDictOffsets = new ArrayList<Integer>(); | List<Integer> privateDictOffsets = new ArrayList<Integer>(); | ||||
List<FontDict> fdFonts = cffReader.getFDFonts(); | List<FontDict> fdFonts = cffReader.getFDFonts(); | ||||
return privateDictOffsets; | return privateDictOffsets; | ||||
} | } | ||||
private int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets, | |||||
protected int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets, | |||||
List<Integer> fontNameSIDs) | List<Integer> fontNameSIDs) | ||||
throws IOException { | throws IOException { | ||||
int offset = currentPos; | int offset = currentPos; | ||||
return c; | return c; | ||||
} | } | ||||
private int writeIndex(List<byte[]> dataArray) { | |||||
protected int writeIndex(List<byte[]> dataArray) { | |||||
int hdrTotal = 3; | int hdrTotal = 3; | ||||
//2 byte number of items | //2 byte number of items | ||||
this.writeCard16(dataArray.size()); | this.writeCard16(dataArray.size()); | ||||
} | } | ||||
} | } | ||||
private void writePrivateDict() throws IOException { | |||||
protected void writePrivateDict() throws IOException { | |||||
Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); | Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); | ||||
DICTEntry privateEntry = topDICT.get("Private"); | DICTEntry privateEntry = topDICT.get("Private"); | ||||
} | } | ||||
} | } | ||||
private void updateOffsets(int topDictOffset, int charsetOffset, int charStringOffset, | |||||
protected void updateOffsets(int topDictOffset, int charsetOffset, int charStringOffset, | |||||
int privateDictOffset, int localIndexOffset, int encodingOffset) | int privateDictOffset, int localIndexOffset, int encodingOffset) | ||||
throws IOException { | throws IOException { | ||||
Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); | Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); | ||||
//Update the local subroutine index offset in the private dict | //Update the local subroutine index offset in the private dict | ||||
DICTEntry subroutines = privateDICT.get("Subrs"); | DICTEntry subroutines = privateDICT.get("Subrs"); | ||||
int oldLocalSubrOffset = privateDictOffset + subroutines.getOffset(); | |||||
//Value needs to be converted to -139 etc. | |||||
int encodeValue = 0; | |||||
if (subroutines.getOperandLength() == 1) { | |||||
encodeValue = 139; | |||||
if (subroutines != null) { | |||||
int oldLocalSubrOffset = privateDictOffset + subroutines.getOffset(); | |||||
//Value needs to be converted to -139 etc. | |||||
int encodeValue = 0; | |||||
if (subroutines.getOperandLength() == 1) { | |||||
encodeValue = 139; | |||||
} | |||||
output = updateOffset(output, oldLocalSubrOffset, subroutines.getOperandLength(), | |||||
(localIndexOffset - privateDictOffset) + encodeValue); | |||||
} | } | ||||
output = updateOffset(output, oldLocalSubrOffset, subroutines.getOperandLength(), | |||||
(localIndexOffset - privateDictOffset) + encodeValue); | |||||
} | } | ||||
} | } | ||||
private void updateFixedOffsets(Map<String, DICTEntry> topDICT, int dataTopDictOffset, | |||||
protected void updateFixedOffsets(Map<String, DICTEntry> topDICT, int dataTopDictOffset, | |||||
int charsetOffset, int charStringOffset, int encodingOffset) { | int charsetOffset, int charStringOffset, int encodingOffset) { | ||||
//Charset offset in the top dict | //Charset offset in the top dict | ||||
DICTEntry charset = topDICT.get("charset"); | DICTEntry charset = topDICT.get("charset"); | ||||
} | } | ||||
} | } | ||||
private void updateCIDOffsets(int topDictDataOffset, int fdArrayOffset, int fdSelectOffset, | |||||
protected void updateCIDOffsets(int topDictDataOffset, int fdArrayOffset, int fdSelectOffset, | |||||
int charsetOffset, int charStringOffset, int encodingOffset) { | int charsetOffset, int charStringOffset, int encodingOffset) { | ||||
LinkedHashMap<String, DICTEntry> topDict = cffReader.getTopDictEntries(); | LinkedHashMap<String, DICTEntry> topDict = cffReader.getTopDictEntries(); | ||||
updateFixedOffsets(topDict, topDictDataOffset, charsetOffset, charStringOffset, encodingOffset); | updateFixedOffsets(topDict, topDictDataOffset, charsetOffset, charStringOffset, encodingOffset); | ||||
} | } | ||||
private byte[] updateOffset(byte[] out, int position, int length, int replacement) { | |||||
protected byte[] updateOffset(byte[] out, int position, int length, int replacement) { | |||||
switch (length) { | switch (length) { | ||||
case 1: | case 1: | ||||
out[position] = (byte)(replacement & 0xFF); | out[position] = (byte)(replacement & 0xFF); | ||||
* Appends a byte to the output array, | * Appends a byte to the output array, | ||||
* updates currentPost but not realSize | * updates currentPost but not realSize | ||||
*/ | */ | ||||
private void writeByte(int b) { | |||||
protected void writeByte(int b) { | |||||
output[currentPos++] = (byte)b; | output[currentPos++] = (byte)b; | ||||
realSize++; | realSize++; | ||||
} | } | ||||
* Appends a USHORT to the output array, | * Appends a USHORT to the output array, | ||||
* updates currentPost but not realSize | * updates currentPost but not realSize | ||||
*/ | */ | ||||
private void writeCard16(int s) { | |||||
protected void writeCard16(int s) { | |||||
byte b1 = (byte)((s >> 8) & 0xff); | byte b1 = (byte)((s >> 8) & 0xff); | ||||
byte b2 = (byte)(s & 0xff); | byte b2 = (byte)(s & 0xff); | ||||
writeByte(b1); | writeByte(b1); | ||||
byte b1 = (byte)((s >> 16) & 0xFF); | byte b1 = (byte)((s >> 16) & 0xFF); | ||||
byte b2 = (byte)((s >> 8) & 0xFF); | byte b2 = (byte)((s >> 8) & 0xFF); | ||||
byte b3 = (byte)(s & 0xFF); | byte b3 = (byte)(s & 0xFF); | ||||
output[currentPos++] = b1; | |||||
output[currentPos++] = b2; | |||||
output[currentPos++] = b3; | |||||
realSize += 3; | |||||
writeByte(b1); | |||||
writeByte(b2); | |||||
writeByte(b3); | |||||
} | } | ||||
/** | /** | ||||
byte b2 = (byte)((s >> 16) & 0xff); | byte b2 = (byte)((s >> 16) & 0xff); | ||||
byte b3 = (byte)((s >> 8) & 0xff); | byte b3 = (byte)((s >> 8) & 0xff); | ||||
byte b4 = (byte)(s & 0xff); | byte b4 = (byte)(s & 0xff); | ||||
output[currentPos++] = b1; | |||||
output[currentPos++] = b2; | |||||
output[currentPos++] = b3; | |||||
output[currentPos++] = b4; | |||||
realSize += 4; | |||||
writeByte(b1); | |||||
writeByte(b2); | |||||
writeByte(b3); | |||||
writeByte(b4); | |||||
} | } | ||||
/** | /** |
protected String notice = ""; | protected String notice = ""; | ||||
protected final Set<String> familyNames = new HashSet<String>(); | protected final Set<String> familyNames = new HashSet<String>(); | ||||
protected String subFamilyName = ""; | protected String subFamilyName = ""; | ||||
protected boolean cid = true; | |||||
private long italicAngle = 0; | private long italicAngle = 0; | ||||
private long isFixedPitch = 0; | private long isFixedPitch = 0; | ||||
unicodeMappings = new ArrayList<OpenFont.UnicodeMapping>(); | unicodeMappings = new ArrayList<OpenFont.UnicodeMapping>(); | ||||
seekTab(fontFile, OFTableName.CMAP, 2); | |||||
if (!seekTab(fontFile, OFTableName.CMAP, 2)) { | |||||
return true; | |||||
} | |||||
int numCMap = fontFile.readTTFUShort(); // Number of cmap subtables | int numCMap = fontFile.readTTFUShort(); // Number of cmap subtables | ||||
long cmapUniOffset = 0; | long cmapUniOffset = 0; | ||||
long symbolMapOffset = 0; | long symbolMapOffset = 0; | ||||
int unicodeStart; | int unicodeStart; | ||||
int glyphStart; | int glyphStart; | ||||
int unicodeEnd; | int unicodeEnd; | ||||
if (unicodeMappings.isEmpty()) { | |||||
return; | |||||
} | |||||
Iterator<UnicodeMapping> e = unicodeMappings.iterator(); | Iterator<UnicodeMapping> e = unicodeMappings.iterator(); | ||||
UnicodeMapping um = e.next(); | UnicodeMapping um = e.next(); | ||||
UnicodeMapping lastMapping = um; | UnicodeMapping lastMapping = um; | ||||
} | } | ||||
} | } | ||||
if (nhmtx < mtxSize) { | |||||
if (cid && nhmtx < mtxSize) { | |||||
// Fill in the missing widths | // Fill in the missing widths | ||||
int lastWidth = mtxTab[nhmtx - 1].getWx(); | int lastWidth = mtxTab[nhmtx - 1].getWx(); | ||||
for (int i = nhmtx; i < mtxSize; i++) { | for (int i = nhmtx; i < mtxSize; i++) { |
*/ | */ | ||||
public class TTFSubSetFile extends TTFFile { | public class TTFSubSetFile extends TTFFile { | ||||
private byte[] output = null; | |||||
private int realSize = 0; | |||||
private int currentPos = 0; | |||||
protected byte[] output = null; | |||||
protected int realSize = 0; | |||||
protected int currentPos = 0; | |||||
/* | /* | ||||
* Offsets in name table to be filled out by table. | * Offsets in name table to be filled out by table. | ||||
* The offsets are to the checkSum field | * The offsets are to the checkSum field | ||||
*/ | */ | ||||
private Map<OFTableName, Integer> offsets = new HashMap<OFTableName, Integer>(); | |||||
protected Map<OFTableName, Integer> offsets = new HashMap<OFTableName, Integer>(); | |||||
private int checkSumAdjustmentOffset = 0; | private int checkSumAdjustmentOffset = 0; | ||||
private int locaOffset = 0; | |||||
protected int locaOffset = 0; | |||||
/** Stores the glyph offsets so that we can end strings at glyph boundaries */ | /** Stores the glyph offsets so that we can end strings at glyph boundaries */ | ||||
private int[] glyphOffsets; | |||||
protected int[] glyphOffsets; | |||||
/** | /** | ||||
* Default Constructor | * Default Constructor | ||||
} | } | ||||
/** The dir tab entries in the new subset font. */ | /** The dir tab entries in the new subset font. */ | ||||
private Map<OFTableName, OFDirTabEntry> newDirTabs | |||||
protected Map<OFTableName, OFDirTabEntry> newDirTabs | |||||
= new HashMap<OFTableName, OFDirTabEntry>(); | = new HashMap<OFTableName, OFDirTabEntry>(); | ||||
private int determineTableCount() { | private int determineTableCount() { | ||||
if (hasPrep()) { | if (hasPrep()) { | ||||
numTables++; | numTables++; | ||||
} | } | ||||
if (!cid) { | |||||
numTables++; //cmap | |||||
} | |||||
} | } | ||||
return numTables; | return numTables; | ||||
} | } | ||||
/** | /** | ||||
* Create the directory table | * Create the directory table | ||||
*/ | */ | ||||
private void createDirectory() { | |||||
protected void createDirectory() { | |||||
int numTables = determineTableCount(); | int numTables = determineTableCount(); | ||||
// Create the TrueType header | // Create the TrueType header | ||||
writeByte((byte)0); | writeByte((byte)0); | ||||
realSize += 2; | realSize += 2; | ||||
// Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) | // Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) | ||||
writeTableName(OFTableName.OS2); | writeTableName(OFTableName.OS2); | ||||
if (!cid) { | |||||
writeTableName(OFTableName.CMAP); | |||||
} | |||||
if (hasCvt()) { | if (hasCvt()) { | ||||
writeTableName(OFTableName.CVT); | writeTableName(OFTableName.CVT); | ||||
} | } | ||||
/** | /** | ||||
* Create an empty loca table without updating checksum | * Create an empty loca table without updating checksum | ||||
*/ | */ | ||||
private void createLoca(int size) throws IOException { | |||||
protected void createLoca(int size) throws IOException { | |||||
pad4(); | pad4(); | ||||
locaOffset = currentPos; | locaOffset = currentPos; | ||||
int dirTableOffset = offsets.get(OFTableName.LOCA); | int dirTableOffset = offsets.get(OFTableName.LOCA); | ||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, tableName, 0); | seekTab(in, tableName, 0); | ||||
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), | |||||
0, output, currentPos, (int)entry.getLength()); | |||||
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); | |||||
updateCheckSum(currentPos, (int) entry.getLength(), tableName); | updateCheckSum(currentPos, (int) entry.getLength(), tableName); | ||||
currentPos += (int) entry.getLength(); | currentPos += (int) entry.getLength(); | ||||
/** | /** | ||||
* Copy the cvt table as is from original font to subset font | * Copy the cvt table as is from original font to subset font | ||||
*/ | */ | ||||
private boolean createCvt(FontFileReader in) throws IOException { | |||||
protected boolean createCvt(FontFileReader in) throws IOException { | |||||
return copyTable(in, OFTableName.CVT); | return copyTable(in, OFTableName.CVT); | ||||
} | } | ||||
/** | /** | ||||
* Copy the fpgm table as is from original font to subset font | * Copy the fpgm table as is from original font to subset font | ||||
*/ | */ | ||||
private boolean createFpgm(FontFileReader in) throws IOException { | |||||
protected boolean createFpgm(FontFileReader in) throws IOException { | |||||
return copyTable(in, OFTableName.FPGM); | return copyTable(in, OFTableName.FPGM); | ||||
} | } | ||||
/** | /** | ||||
* Copy the name table as is from the original. | * Copy the name table as is from the original. | ||||
*/ | */ | ||||
private boolean createName(FontFileReader in) throws IOException { | |||||
protected boolean createName(FontFileReader in) throws IOException { | |||||
return copyTable(in, OFTableName.NAME); | return copyTable(in, OFTableName.NAME); | ||||
} | } | ||||
/** | /** | ||||
* Copy the OS/2 table as is from the original. | * Copy the OS/2 table as is from the original. | ||||
*/ | */ | ||||
private boolean createOS2(FontFileReader in) throws IOException { | |||||
protected boolean createOS2(FontFileReader in) throws IOException { | |||||
return copyTable(in, OFTableName.OS2); | return copyTable(in, OFTableName.OS2); | ||||
} | } | ||||
* Copy the maxp table as is from original font to subset font | * Copy the maxp table as is from original font to subset font | ||||
* and set num glyphs to size | * and set num glyphs to size | ||||
*/ | */ | ||||
private void createMaxp(FontFileReader in, int size) throws IOException { | |||||
protected void createMaxp(FontFileReader in, int size) throws IOException { | |||||
OFTableName maxp = OFTableName.MAXP; | OFTableName maxp = OFTableName.MAXP; | ||||
OFDirTabEntry entry = dirTabs.get(maxp); | OFDirTabEntry entry = dirTabs.get(maxp); | ||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, maxp, 0); | seekTab(in, maxp, 0); | ||||
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), | |||||
0, output, currentPos, (int)entry.getLength()); | |||||
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); | |||||
writeUShort(currentPos + 4, size); | writeUShort(currentPos + 4, size); | ||||
updateCheckSum(currentPos, (int)entry.getLength(), maxp); | updateCheckSum(currentPos, (int)entry.getLength(), maxp); | ||||
} | } | ||||
} | } | ||||
private void createPost(FontFileReader in) throws IOException { | |||||
protected void createPost(FontFileReader in) throws IOException { | |||||
OFTableName post = OFTableName.POST; | OFTableName post = OFTableName.POST; | ||||
OFDirTabEntry entry = dirTabs.get(post); | OFDirTabEntry entry = dirTabs.get(post); | ||||
if (entry != null) { | if (entry != null) { | ||||
0, newPostTable, 0, newTableSize); | 0, newPostTable, 0, newTableSize); | ||||
// set the post table to Format 3.0 | // set the post table to Format 3.0 | ||||
newPostTable[1] = 0x03; | newPostTable[1] = 0x03; | ||||
System.arraycopy(newPostTable, 0, output, currentPos, newTableSize); | |||||
writeBytes(newPostTable); | |||||
updateCheckSum(currentPos, newTableSize, post); | updateCheckSum(currentPos, newTableSize, post); | ||||
currentPos += newTableSize; | currentPos += newTableSize; | ||||
realSize += newTableSize; | realSize += newTableSize; | ||||
} else { | } else { | ||||
throw new IOException("Can't find post table"); | |||||
// throw new IOException("Can't find post table"); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Copy the prep table as is from original font to subset font | * Copy the prep table as is from original font to subset font | ||||
*/ | */ | ||||
private boolean createPrep(FontFileReader in) throws IOException { | |||||
protected boolean createPrep(FontFileReader in) throws IOException { | |||||
return copyTable(in, OFTableName.PREP); | return copyTable(in, OFTableName.PREP); | ||||
} | } | ||||
* Copy the hhea table as is from original font to subset font | * Copy the hhea table as is from original font to subset font | ||||
* and fill in size of hmtx table | * and fill in size of hmtx table | ||||
*/ | */ | ||||
private void createHhea(FontFileReader in, int size) throws IOException { | |||||
protected void createHhea(FontFileReader in, int size) throws IOException { | |||||
OFDirTabEntry entry = dirTabs.get(OFTableName.HHEA); | OFDirTabEntry entry = dirTabs.get(OFTableName.HHEA); | ||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, OFTableName.HHEA, 0); | seekTab(in, OFTableName.HHEA, 0); | ||||
System.arraycopy(in.getBytes((int) entry.getOffset(), (int) entry.getLength()), 0, | |||||
output, currentPos, (int) entry.getLength()); | |||||
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); | |||||
writeUShort((int) entry.getLength() + currentPos - 2, size); | writeUShort((int) entry.getLength() + currentPos - 2, size); | ||||
updateCheckSum(currentPos, (int) entry.getLength(), OFTableName.HHEA); | updateCheckSum(currentPos, (int) entry.getLength(), OFTableName.HHEA); | ||||
* checkSumAdjustment to 0, store offset to checkSumAdjustment | * checkSumAdjustment to 0, store offset to checkSumAdjustment | ||||
* in checkSumAdjustmentOffset | * in checkSumAdjustmentOffset | ||||
*/ | */ | ||||
private void createHead(FontFileReader in) throws IOException { | |||||
protected void createHead(FontFileReader in) throws IOException { | |||||
OFTableName head = OFTableName.HEAD; | OFTableName head = OFTableName.HEAD; | ||||
OFDirTabEntry entry = dirTabs.get(head); | OFDirTabEntry entry = dirTabs.get(head); | ||||
if (entry != null) { | if (entry != null) { | ||||
pad4(); | pad4(); | ||||
seekTab(in, head, 0); | seekTab(in, head, 0); | ||||
System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()), | |||||
0, output, currentPos, (int)entry.getLength()); | |||||
writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); | |||||
checkSumAdjustmentOffset = currentPos + 8; | checkSumAdjustmentOffset = currentPos + 8; | ||||
output[currentPos + 8] = 0; // Set checkSumAdjustment to 0 | output[currentPos + 8] = 0; // Set checkSumAdjustment to 0 | ||||
output[currentPos + 10] = 0; | output[currentPos + 10] = 0; | ||||
output[currentPos + 11] = 0; | output[currentPos + 11] = 0; | ||||
output[currentPos + 50] = 0; // long locaformat | output[currentPos + 50] = 0; // long locaformat | ||||
output[currentPos + 51] = 1; // long locaformat | |||||
if (cid) { | |||||
output[currentPos + 51] = 1; // long locaformat | |||||
} | |||||
updateCheckSum(currentPos, (int)entry.getLength(), head); | updateCheckSum(currentPos, (int)entry.getLength(), head); | ||||
currentPos += (int)entry.getLength(); | currentPos += (int)entry.getLength(); | ||||
realSize += (int)entry.getLength(); | realSize += (int)entry.getLength(); | ||||
glyphLength); | glyphLength); | ||||
int endOffset1 = endOffset; | int endOffset1 = endOffset; | ||||
// Copy glyph | // Copy glyph | ||||
System.arraycopy( | |||||
glyphData, 0, | |||||
output, currentPos, | |||||
glyphLength); | |||||
writeBytes(glyphData); | |||||
// Update loca table | // Update loca table | ||||
} | } | ||||
} | } | ||||
private int[] buildSubsetIndexToOrigIndexMap(Map<Integer, Integer> glyphs) { | |||||
protected int[] buildSubsetIndexToOrigIndexMap(Map<Integer, Integer> glyphs) { | |||||
int[] origIndexes = new int[glyphs.size()]; | int[] origIndexes = new int[glyphs.size()]; | ||||
for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) { | for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) { | ||||
int origIndex = glyph.getKey(); | int origIndex = glyph.getKey(); | ||||
int subsetIndex = glyph.getValue(); | int subsetIndex = glyph.getValue(); | ||||
origIndexes[subsetIndex] = origIndex; | |||||
if (origIndexes.length > subsetIndex) { | |||||
origIndexes[subsetIndex] = origIndex; | |||||
} | |||||
} | } | ||||
return origIndexes; | return origIndexes; | ||||
} | } | ||||
* Integer key and Integer value that maps the original | * Integer key and Integer value that maps the original | ||||
* metric (key) to the subset metric (value) | * metric (key) to the subset metric (value) | ||||
*/ | */ | ||||
private void createHmtx(FontFileReader in, | |||||
Map<Integer, Integer> glyphs) throws IOException { | |||||
protected void createHmtx(FontFileReader in, | |||||
Map<Integer, Integer> glyphs) throws IOException { | |||||
OFTableName hmtx = OFTableName.HMTX; | OFTableName hmtx = OFTableName.HMTX; | ||||
OFDirTabEntry entry = dirTabs.get(hmtx); | OFDirTabEntry entry = dirTabs.get(hmtx); | ||||
ttfOut.endFontStream(); | ttfOut.endFontStream(); | ||||
} | } | ||||
private void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs) | |||||
protected void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs) | |||||
throws IOException { | throws IOException { | ||||
OFDirTabEntry glyfTableInfo = dirTabs.get(OFTableName.GLYF); | OFDirTabEntry glyfTableInfo = dirTabs.get(OFTableName.GLYF); | ||||
if (glyfTableInfo == null) { | if (glyfTableInfo == null) { | ||||
int length = 0; | int length = 0; | ||||
try { | try { | ||||
byte[] buf = str.getBytes("ISO-8859-1"); | byte[] buf = str.getBytes("ISO-8859-1"); | ||||
System.arraycopy(buf, 0, output, currentPos, buf.length); | |||||
writeBytes(buf); | |||||
length = buf.length; | length = buf.length; | ||||
currentPos += length; | currentPos += length; | ||||
} catch (java.io.UnsupportedEncodingException e) { | } catch (java.io.UnsupportedEncodingException e) { | ||||
output[currentPos++] = b; | output[currentPos++] = b; | ||||
} | } | ||||
protected void writeBytes(byte[] b) { | |||||
if (b.length + currentPos > output.length) { | |||||
byte[] newoutput = new byte[output.length * 2]; | |||||
System.arraycopy(output, 0, newoutput, 0, output.length); | |||||
output = newoutput; | |||||
} | |||||
System.arraycopy(b, 0, output, currentPos, b.length); | |||||
} | |||||
/** | /** | ||||
* Appends a USHORT to the output array, | * Appends a USHORT to the output array, | ||||
* updates currentPost but not realSize | * updates currentPost but not realSize | ||||
*/ | */ | ||||
private void writeUShort(int s) { | |||||
protected void writeUShort(int s) { | |||||
byte b1 = (byte)((s >> 8) & 0xff); | byte b1 = (byte)((s >> 8) & 0xff); | ||||
byte b2 = (byte)(s & 0xff); | byte b2 = (byte)(s & 0xff); | ||||
writeByte(b1); | writeByte(b1); | ||||
* Appends a USHORT to the output array, | * Appends a USHORT to the output array, | ||||
* at the given position without changing currentPos | * at the given position without changing currentPos | ||||
*/ | */ | ||||
private void writeUShort(int pos, int s) { | |||||
protected void writeUShort(int pos, int s) { | |||||
byte b1 = (byte)((s >> 8) & 0xff); | byte b1 = (byte)((s >> 8) & 0xff); | ||||
byte b2 = (byte)(s & 0xff); | byte b2 = (byte)(s & 0xff); | ||||
output[pos] = b1; | output[pos] = b1; | ||||
* Appends a ULONG to the output array, | * Appends a ULONG to the output array, | ||||
* at the given position without changing currentPos | * at the given position without changing currentPos | ||||
*/ | */ | ||||
private void writeULong(int pos, int s) { | |||||
protected void writeULong(int pos, int s) { | |||||
byte b1 = (byte)((s >> 24) & 0xff); | byte b1 = (byte)((s >> 24) & 0xff); | ||||
byte b2 = (byte)((s >> 16) & 0xff); | byte b2 = (byte)((s >> 16) & 0xff); | ||||
byte b3 = (byte)((s >> 8) & 0xff); | byte b3 = (byte)((s >> 8) & 0xff); | ||||
* Create a padding in the fontfile to align | * Create a padding in the fontfile to align | ||||
* on a 4-byte boundary | * on a 4-byte boundary | ||||
*/ | */ | ||||
private void pad4() { | |||||
protected void pad4() { | |||||
int padSize = getPadSize(currentPos); | int padSize = getPadSize(currentPos); | ||||
if (padSize < 4) { | if (padSize < 4) { | ||||
for (int i = 0; i < padSize; i++) { | for (int i = 0; i < padSize; i++) { | ||||
} | } | ||||
private void updateCheckSum(int tableStart, int tableSize, OFTableName tableName) { | |||||
protected void updateCheckSum(int tableStart, int tableSize, OFTableName tableName) { | |||||
int checksum = getCheckSum(output, tableStart, tableSize); | int checksum = getCheckSum(output, tableStart, tableSize); | ||||
int offset = offsets.get(tableName); | int offset = offsets.get(tableName); | ||||
int padSize = getPadSize(tableStart + tableSize); | int padSize = getPadSize(tableStart + tableSize); | ||||
writeULong(offset + 8, tableSize); | writeULong(offset + 8, tableSize); | ||||
} | } | ||||
private static int getCheckSum(byte[] data, int start, int size) { | |||||
protected static int getCheckSum(byte[] data, int start, int size) { | |||||
// All the tables here are aligned on four byte boundaries | // All the tables here are aligned on four byte boundaries | ||||
// Add remainder to size if it's not a multiple of 4 | // Add remainder to size if it's not a multiple of 4 | ||||
int remainder = size % 4; | int remainder = size % 4; | ||||
long l = 0; | long l = 0; | ||||
for (int j = 0; j < 4; j++) { | for (int j = 0; j < 4; j++) { | ||||
l <<= 8; | l <<= 8; | ||||
l |= data[start + i + j] & 0xff; | |||||
if (data.length > (start + i + j)) { | |||||
l |= data[start + i + j] & 0xff; | |||||
} | |||||
} | } | ||||
sum += l; | sum += l; | ||||
} | } | ||||
return (int) sum; | return (int) sum; | ||||
} | } | ||||
private void createCheckSumAdjustment() { | |||||
protected void createCheckSumAdjustment() { | |||||
long sum = getCheckSum(output, 0, realSize); | long sum = getCheckSum(output, 0, realSize); | ||||
int checksum = (int)(0xb1b0afba - sum); | int checksum = (int)(0xb1b0afba - sum); | ||||
writeULong(checkSumAdjustmentOffset, checksum); | writeULong(checkSumAdjustmentOffset, checksum); |
return dictionary; | return dictionary; | ||||
} | } | ||||
protected Object get(String key) { | |||||
public Object get(String key) { | |||||
return dictionary.get(key); | return dictionary.get(key); | ||||
} | } | ||||
/* | |||||
* 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.pdf; | |||||
import java.io.IOException; | |||||
import java.io.OutputStream; | |||||
/** | |||||
* Special PDFStream for embeddable CFF fonts. | |||||
*/ | |||||
public class PDFCFFStream extends AbstractPDFFontStream { | |||||
private byte[] cffData; | |||||
private String type; | |||||
public PDFCFFStream(String type) { | |||||
this.type = type; | |||||
} | |||||
protected int getSizeHint() throws IOException { | |||||
if (this.cffData != null) { | |||||
return cffData.length; | |||||
} else { | |||||
return 0; //no hint available | |||||
} | |||||
} | |||||
protected void outputRawStreamData(OutputStream out) throws IOException { | |||||
out.write(this.cffData); | |||||
} | |||||
protected void populateStreamDict(Object lengthEntry) { | |||||
put("Subtype", new PDFName(type)); | |||||
super.populateStreamDict(lengthEntry); | |||||
} | |||||
public void setData(byte[] data) throws IOException { | |||||
cffData = data; | |||||
} | |||||
} |
private boolean accessibilityEnabled; | private boolean accessibilityEnabled; | ||||
private boolean mergeFontsEnabled; | |||||
/** | /** | ||||
* Creates an empty PDF document. | * Creates an empty PDF document. | ||||
* | * | ||||
return trailerDictionary; | return trailerDictionary; | ||||
} | } | ||||
public boolean isMergeFontsEnabled() { | |||||
return mergeFontsEnabled; | |||||
} | |||||
public void setMergeFontsEnabled(boolean mergeFontsEnabled) { | |||||
this.mergeFontsEnabled = mergeFontsEnabled; | |||||
} | |||||
private interface TrailerOutputHelper { | private interface TrailerOutputHelper { | ||||
void outputStructureTreeElements(OutputStream stream) throws IOException; | void outputStructureTreeElements(OutputStream stream) throws IOException; |
PDFFont font = null; | PDFFont font = null; | ||||
font = PDFFont.createFont(fontname, fonttype, subsetFontName, null); | font = PDFFont.createFont(fontname, fonttype, subsetFontName, null); | ||||
getDocument().registerObject(font); | |||||
if (descriptor instanceof RefPDFFont) { | |||||
font.setObjectNumber(((RefPDFFont)descriptor).getRef().getObjectNumber()); | |||||
font.setDocument(getDocument()); | |||||
getDocument().addObject(font); | |||||
} else { | |||||
getDocument().registerObject(font); | |||||
} | |||||
if (fonttype == FontType.TYPE0) { | |||||
if ((fonttype == FontType.TYPE0 || fonttype == FontType.CIDTYPE0)) { | |||||
font.setEncoding(encoding); | font.setEncoding(encoding); | ||||
CIDFont cidMetrics; | CIDFont cidMetrics; | ||||
if (metrics instanceof LazyFont) { | if (metrics instanceof LazyFont) { | ||||
PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(), | PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(), | ||||
cidMetrics.getOrdering(), cidMetrics.getSupplement()); | cidMetrics.getOrdering(), cidMetrics.getSupplement()); | ||||
sysInfo.setDocument(document); | sysInfo.setDocument(document); | ||||
assert pdfdesc instanceof PDFCIDFontDescriptor; | |||||
PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(), | PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(), | ||||
cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo, | cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo, | ||||
(PDFCIDFontDescriptor) pdfdesc); | (PDFCIDFontDescriptor) pdfdesc); | ||||
getDocument().registerObject(cidFont); | getDocument().registerObject(cidFont); | ||||
PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H", | |||||
PDFCMap cmap; | |||||
if (cidMetrics instanceof MultiByteFont && ((MultiByteFont) cidMetrics).getCmapStream() != null) { | |||||
cmap = new PDFCMap("fop-ucs-H", null); | |||||
try { | |||||
cmap.setData(IOUtils.toByteArray(((MultiByteFont) cidMetrics).getCmapStream())); | |||||
} catch (IOException e) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
} else { | |||||
cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H", | |||||
new PDFCIDSystemInfo("Adobe", "Identity", 0), false); | new PDFCIDSystemInfo("Adobe", "Identity", 0), false); | ||||
} | |||||
getDocument().registerObject(cmap); | getDocument().registerObject(cmap); | ||||
assert font instanceof PDFFontType0; | |||||
((PDFFontType0)font).setCMAP(cmap); | ((PDFFontType0)font).setCMAP(cmap); | ||||
((PDFFontType0)font).setDescendantFonts(cidFont); | ((PDFFontType0)font).setDescendantFonts(cidFont); | ||||
} else { | } else { | ||||
assert font instanceof PDFFontNonBase14; | |||||
PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font; | PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font; | ||||
nonBase14.setDescriptor(pdfdesc); | nonBase14.setDescriptor(pdfdesc); | ||||
font.setEncoding(mapping.getName()); | font.setEncoding(mapping.getName()); | ||||
//No ToUnicode CMap necessary if PDF 1.4, chapter 5.9 (page 368) is to be | //No ToUnicode CMap necessary if PDF 1.4, chapter 5.9 (page 368) is to be | ||||
//believed. | //believed. | ||||
} else if (mapping.getName().equals("FOPPDFEncoding")) { | |||||
String[] charNameMap = mapping.getCharNameMap(); | |||||
char[] intmap = mapping.getUnicodeCharMap(); | |||||
PDFArray differences = new PDFArray(); | |||||
int len = intmap.length; | |||||
if (charNameMap.length < len) { | |||||
len = charNameMap.length; | |||||
} | |||||
int last = 0; | |||||
for (int i = 0; i < len; i++) { | |||||
if (intmap[i] - 1 != last) { | |||||
differences.add(intmap[i]); | |||||
} | |||||
last = intmap[i]; | |||||
differences.add(new PDFName(charNameMap[i])); | |||||
} | |||||
PDFEncoding pdfEncoding = new PDFEncoding(singleByteFont.getEncodingName()); | |||||
getDocument().registerObject(pdfEncoding); | |||||
pdfEncoding.setDifferences(differences); | |||||
font.setEncoding(pdfEncoding); | |||||
if (mapping.getUnicodeCharMap() != null) { | |||||
generateToUnicodeCmap(nonBase14, mapping); | |||||
} | |||||
} else { | } else { | ||||
Object pdfEncoding = createPDFEncoding(mapping, | Object pdfEncoding = createPDFEncoding(mapping, | ||||
singleByteFont.getFontName()); | singleByteFont.getFontName()); | ||||
private PDFWArray getFontWidths(CIDFont cidFont) { | private PDFWArray getFontWidths(CIDFont cidFont) { | ||||
// Create widths for reencoded chars | // Create widths for reencoded chars | ||||
PDFWArray warray = new PDFWArray(); | PDFWArray warray = new PDFWArray(); | ||||
int[] widths = cidFont.getCIDSet().getWidths(); | |||||
warray.addEntry(0, widths); | |||||
if (cidFont instanceof MultiByteFont && ((MultiByteFont)cidFont).getWidthsMap() != null) { | |||||
Map<Integer, Integer> map = ((MultiByteFont)cidFont).getWidthsMap(); | |||||
for (Map.Entry<Integer, Integer> cid : map.entrySet()) { | |||||
warray.addEntry(cid.getKey(), new int[] {cid.getValue()}); | |||||
} | |||||
// List<Integer> l = new ArrayList<Integer>(map.keySet()); | |||||
// for (int i=0; i<map.size(); i++) { | |||||
// int cid = l.get(i); | |||||
// List<Integer> cids = new ArrayList<Integer>(); | |||||
// cids.add(map.get(cid)); | |||||
// while (i<map.size()-1 && l.get(i) + 1 == l.get(i + 1)) { | |||||
// cids.add(map.get(l.get(i + 1))); | |||||
// i++; | |||||
// } | |||||
// int[] cidsints = new int[cids.size()]; | |||||
// for (int j=0; j<cids.size(); j++) { | |||||
// cidsints[j] = cids.get(j); | |||||
// } | |||||
// warray.addEntry(cid, cidsints); | |||||
// } | |||||
} else { | |||||
int[] widths = cidFont.getCIDSet().getWidths(); | |||||
warray.addEntry(0, widths); | |||||
} | |||||
return warray; | return warray; | ||||
} | } | ||||
private PDFFontDescriptor makeFontDescriptor(FontDescriptor desc, String fontPrefix) { | private PDFFontDescriptor makeFontDescriptor(FontDescriptor desc, String fontPrefix) { | ||||
PDFFontDescriptor descriptor = null; | PDFFontDescriptor descriptor = null; | ||||
if (desc.getFontType() == FontType.TYPE0) { | |||||
if (desc.getFontType() == FontType.TYPE0 || desc.getFontType() == FontType.CIDTYPE0) { | |||||
// CID Font | // CID Font | ||||
descriptor = new PDFCIDFontDescriptor(fontPrefix + desc.getEmbedFontName(), | descriptor = new PDFCIDFontDescriptor(fontPrefix + desc.getEmbedFontName(), | ||||
desc.getFontBBox(), | desc.getFontBBox(), | ||||
in = font.getInputStream(); | in = font.getInputStream(); | ||||
if (in == null) { | if (in == null) { | ||||
return null; | return null; | ||||
} else { | |||||
AbstractPDFStream embeddedFont = null; | |||||
if (desc.getFontType() == FontType.TYPE0) { | |||||
MultiByteFont mbfont = (MultiByteFont) font; | |||||
FontFileReader reader = new FontFileReader(in); | |||||
byte[] fontBytes; | |||||
String header = OFFontLoader.readHeader(reader); | |||||
boolean isCFF = mbfont.isOTFFile(); | |||||
if (font.getEmbeddingMode() == EmbeddingMode.FULL) { | |||||
fontBytes = reader.getAllBytes(); | |||||
if (isCFF) { | |||||
//Ensure version 1.6 for full OTF CFF embedding | |||||
document.setPDFVersion(Version.V1_6); | |||||
} | |||||
} else { | |||||
fontBytes = getFontSubsetBytes(reader, mbfont, header, fontPrefix, desc, | |||||
isCFF); | |||||
} | |||||
embeddedFont = getFontStream(font, fontBytes, isCFF); | |||||
} else if (desc.getFontType() == FontType.TYPE1) { | |||||
if (font.getEmbeddingMode() != EmbeddingMode.SUBSET) { | |||||
embeddedFont = fullyEmbedType1Font(in); | |||||
} else { | |||||
assert font instanceof SingleByteFont; | |||||
SingleByteFont sbfont = (SingleByteFont)font; | |||||
Type1SubsetFile pfbFile = new Type1SubsetFile(); | |||||
byte[] subsetData = pfbFile.createSubset(in, sbfont, fontPrefix); | |||||
InputStream subsetStream = new ByteArrayInputStream(subsetData); | |||||
PFBParser parser = new PFBParser(); | |||||
PFBData pfb = parser.parsePFB(subsetStream); | |||||
embeddedFont = new PDFT1Stream(); | |||||
((PDFT1Stream) embeddedFont).setData(pfb); | |||||
} | |||||
AbstractPDFStream embeddedFont = null; | |||||
if (desc.getFontType() == FontType.TYPE0) { | |||||
MultiByteFont mbfont = (MultiByteFont) font; | |||||
FontFileReader reader = new FontFileReader(in); | |||||
byte[] fontBytes; | |||||
String header = OFFontLoader.readHeader(reader); | |||||
boolean isCFF = mbfont.isOTFFile(); | |||||
if (font.getEmbeddingMode() == EmbeddingMode.FULL) { | |||||
fontBytes = reader.getAllBytes(); | |||||
if (isCFF) { | |||||
//Ensure version 1.6 for full OTF CFF embedding | |||||
document.setPDFVersion(Version.V1_6); | |||||
} | } | ||||
} else { | } else { | ||||
byte[] file = IOUtils.toByteArray(in); | |||||
embeddedFont = new PDFTTFStream(file.length); | |||||
((PDFTTFStream) embeddedFont).setData(file, file.length); | |||||
fontBytes = getFontSubsetBytes(reader, mbfont, header, fontPrefix, desc, | |||||
isCFF); | |||||
} | } | ||||
/* | |||||
embeddedFont.getFilterList().addFilter("flate"); | |||||
if (getDocument().isEncryptionActive()) { | |||||
getDocument().applyEncryption(embeddedFont); | |||||
embeddedFont = getFontStream(font, fontBytes, isCFF); | |||||
} else if (desc.getFontType() == FontType.TYPE1) { | |||||
if (font.getEmbeddingMode() != EmbeddingMode.SUBSET) { | |||||
embeddedFont = fullyEmbedType1Font(in); | |||||
} else { | } else { | ||||
embeddedFont.getFilterList().addFilter("ascii-85"); | |||||
}*/ | |||||
return embeddedFont; | |||||
assert font instanceof SingleByteFont; | |||||
SingleByteFont sbfont = (SingleByteFont)font; | |||||
Type1SubsetFile pfbFile = new Type1SubsetFile(); | |||||
byte[] subsetData = pfbFile.createSubset(in, sbfont, fontPrefix); | |||||
InputStream subsetStream = new ByteArrayInputStream(subsetData); | |||||
PFBParser parser = new PFBParser(); | |||||
PFBData pfb = parser.parsePFB(subsetStream); | |||||
embeddedFont = new PDFT1Stream(); | |||||
((PDFT1Stream) embeddedFont).setData(pfb); | |||||
} | |||||
} else if (desc.getFontType() == FontType.TYPE1C) { | |||||
byte[] file = IOUtils.toByteArray(in); | |||||
PDFCFFStream embeddedFont2 = new PDFCFFStream("Type1C"); | |||||
embeddedFont2.setData(file); | |||||
return embeddedFont2; | |||||
} else if (desc.getFontType() == FontType.CIDTYPE0) { | |||||
byte[] file = IOUtils.toByteArray(in); | |||||
PDFCFFStream embeddedFont2 = new PDFCFFStream("CIDFontType0C"); | |||||
embeddedFont2.setData(file); | |||||
return embeddedFont2; | |||||
} else { | |||||
byte[] file = IOUtils.toByteArray(in); | |||||
embeddedFont = new PDFTTFStream(file.length); | |||||
((PDFTTFStream) embeddedFont).setData(file, file.length); | |||||
} | } | ||||
/* | |||||
embeddedFont.getFilterList().addFilter("flate"); | |||||
if (getDocument().isEncryptionActive()) { | |||||
getDocument().applyEncryption(embeddedFont); | |||||
} else { | |||||
embeddedFont.getFilterList().addFilter("ascii-85"); | |||||
}*/ | |||||
return embeddedFont; | |||||
} catch (IOException ioe) { | } catch (IOException ioe) { | ||||
log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe); | log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe); | ||||
return null; | return null; |
public static PDFFont createFont(String fontname, | public static PDFFont createFont(String fontname, | ||||
FontType subtype, String basefont, | FontType subtype, String basefont, | ||||
Object encoding) { | Object encoding) { | ||||
if (subtype == FontType.TYPE0) { | |||||
if (subtype == FontType.TYPE0 || subtype == FontType.CIDTYPE0) { | |||||
return new PDFFontType0(fontname, basefont, | return new PDFFontType0(fontname, basefont, | ||||
encoding); | encoding); | ||||
} else if ((subtype == FontType.TYPE1) | } else if ((subtype == FontType.TYPE1) | ||||
|| (subtype == FontType.TYPE1C) | |||||
|| (subtype == FontType.MMTYPE1)) { | || (subtype == FontType.MMTYPE1)) { | ||||
return new PDFFontType1(fontname, basefont, | return new PDFFontType1(fontname, basefont, | ||||
encoding); | encoding); |
public void setFontFile(FontType subtype, AbstractPDFStream fontfile) { | public void setFontFile(FontType subtype, AbstractPDFStream fontfile) { | ||||
if (subtype == FontType.TYPE1) { | if (subtype == FontType.TYPE1) { | ||||
put("FontFile", fontfile); | put("FontFile", fontfile); | ||||
} else if (fontfile instanceof PDFCFFStreamType0C) { | |||||
} else if (fontfile instanceof PDFCFFStreamType0C || subtype == FontType.TYPE1C) { | |||||
put("FontFile3", fontfile); | put("FontFile3", fontfile); | ||||
} else { | } else { | ||||
put("FontFile2", fontfile); | put("FontFile2", fontfile); |
/* | |||||
* 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. | |||||
*/ | |||||
package org.apache.fop.pdf; | |||||
public interface RefPDFFont { | |||||
PDFDictionary getRef(); | |||||
} |
if (log.isTraceEnabled()) { | if (log.isTraceEnabled()) { | ||||
log.trace("Using ImageHandler: " + handler.getClass().getName()); | log.trace("Using ImageHandler: " + handler.getClass().getName()); | ||||
} | } | ||||
context.putHint("fontinfo", getFontInfo()); | |||||
handler.handleImage(context, effImage, rect); | handler.handleImage(context, effImage, rect); | ||||
} | } | ||||
import static org.apache.fop.render.pdf.PDFEncryptionOption.USER_PASSWORD; | import static org.apache.fop.render.pdf.PDFEncryptionOption.USER_PASSWORD; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; | import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; | import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.MERGE_FONTS; | |||||
import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; | import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; | import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; | import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; | ||||
configureEncryptionParams(cfg, userAgent, strict); | configureEncryptionParams(cfg, userAgent, strict); | ||||
parseAndPut(OUTPUT_PROFILE, cfg); | parseAndPut(OUTPUT_PROFILE, cfg); | ||||
parseAndPut(DISABLE_SRGB_COLORSPACE, cfg); | parseAndPut(DISABLE_SRGB_COLORSPACE, cfg); | ||||
parseAndPut(MERGE_FONTS, cfg); | |||||
parseAndPut(VERSION, cfg); | parseAndPut(VERSION, cfg); | ||||
} catch (ConfigurationException e) { | } catch (ConfigurationException e) { |
return Boolean.valueOf(value); | return Boolean.valueOf(value); | ||||
} | } | ||||
}, | }, | ||||
MERGE_FONTS("merge-fonts", false) { | |||||
@Override | |||||
Boolean deserialize(String value) { | |||||
return Boolean.valueOf(value); | |||||
} | |||||
}, | |||||
/** Rendering Options key for the ICC profile for the output intent. */ | /** Rendering Options key for the ICC profile for the output intent. */ | ||||
OUTPUT_PROFILE("output-profile") { | OUTPUT_PROFILE("output-profile") { | ||||
@Override | @Override |
import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; | import static org.apache.fop.render.pdf.PDFRendererOption.DISABLE_SRGB_COLORSPACE; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; | import static org.apache.fop.render.pdf.PDFRendererOption.FILTER_LIST; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.MERGE_FONTS; | |||||
import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; | import static org.apache.fop.render.pdf.PDFRendererOption.OUTPUT_PROFILE; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; | import static org.apache.fop.render.pdf.PDFRendererOption.PDF_A_MODE; | ||||
import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; | import static org.apache.fop.render.pdf.PDFRendererOption.PDF_X_MODE; | ||||
public Version getPDFVersion() { | public Version getPDFVersion() { | ||||
return (Version) properties.get(VERSION); | return (Version) properties.get(VERSION); | ||||
} | } | ||||
public Boolean getMergeFontsEnabled() { | |||||
return (Boolean)properties.get(MERGE_FONTS); | |||||
} | |||||
} | } |
} | } | ||||
this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled()); | this.pdfDoc.enableAccessibility(userAgent.isAccessibilityEnabled()); | ||||
pdfDoc.setMergeFontsEnabled(rendererConfig.getMergeFontsEnabled()); | |||||
return this.pdfDoc; | return this.pdfDoc; | ||||
} | } |