git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1384690 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -29,7 +29,7 @@ import org.apache.fop.apps.io.InternalResourceResolver; | |||
public abstract class CIDFont extends CustomFont { | |||
/** Contains the character widths for all characters in the font */ | |||
protected int[] width = null; | |||
protected int[] width; | |||
/** | |||
* @param resourceResolver the URI resolver for controlling file access | |||
@@ -69,7 +69,7 @@ public abstract class CIDFont extends CustomFont { | |||
* Returns the subset information for this font. | |||
* @return the subset information | |||
*/ | |||
public abstract CIDSubset getCIDSubset(); | |||
public abstract CIDSet getCIDSet(); | |||
// ---- Optional ---- | |||
/** |
@@ -0,0 +1,113 @@ | |||
/* | |||
* 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.fonts; | |||
import java.util.BitSet; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.fop.util.CharUtilities; | |||
/** | |||
* Provides methods to get font information. | |||
* Naming: | |||
* glyph index: original index of the glyph in the non-subset font (!= unicode index) | |||
* character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset | |||
* fonts, this is the same as the glyph index. | |||
* Unicode index: The Unicode codepoint of a character. | |||
* Glyph name: the Adobe glyph name (as found in Glyphs.java) | |||
*/ | |||
public class CIDFull implements CIDSet { | |||
private BitSet glyphIndices; | |||
private final MultiByteFont font; | |||
public CIDFull(MultiByteFont mbf) { | |||
font = mbf; | |||
} | |||
private void initGlyphIndices() { | |||
// this cannot be called in the constructor since the font is not ready... | |||
if (glyphIndices == null) { | |||
glyphIndices = font.getGlyphIndices(); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public int getOriginalGlyphIndex(int index) { | |||
return index; | |||
} | |||
/** {@inheritDoc} */ | |||
public char getUnicode(int index) { | |||
initGlyphIndices(); | |||
if (glyphIndices.get(index)) { | |||
return (char) index; | |||
} else { | |||
return CharUtilities.NOT_A_CHARACTER; | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public int mapChar(int glyphIndex, char unicode) { | |||
return (char) glyphIndex; | |||
} | |||
/** {@inheritDoc} */ | |||
public Map<Integer, Integer> getGlyphs() { | |||
// this is never really called for full embedded fonts but the equivalent map would be the identity | |||
initGlyphIndices(); | |||
Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>(); | |||
int nextBitSet = 0; | |||
for (int j = 0; j < glyphIndices.cardinality(); j++) { | |||
nextBitSet = glyphIndices.nextSetBit(nextBitSet); | |||
glyphs.put(Integer.valueOf(nextBitSet), Integer.valueOf(nextBitSet)); | |||
nextBitSet++; | |||
} | |||
return Collections.unmodifiableMap(glyphs); | |||
} | |||
/** {@inheritDoc} */ | |||
public char[] getChars() { | |||
return font.getChars(); | |||
} | |||
/** {@inheritDoc} */ | |||
public int getNumberOfGlyphs() { | |||
initGlyphIndices(); | |||
// note: the real number of glyphs is given by the cardinality() method (not the length()) but since | |||
// we will pad gaps in the indices with zeros we really want the length() here. this method is only | |||
// called when embedding a font in PostScript and this will be the value of the CIDCount entry | |||
return glyphIndices.length(); | |||
} | |||
/** {@inheritDoc} */ | |||
public BitSet getGlyphIndices() { | |||
initGlyphIndices(); | |||
return glyphIndices; | |||
} | |||
/** {@inheritDoc} */ | |||
public int[] getWidths() { | |||
return font.getWidths(); | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
/* | |||
* 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.fonts; | |||
import java.util.BitSet; | |||
import java.util.Map; | |||
/** | |||
* Declares methods to retrieve font information (glyph indices, widths, unicode values) from a CID font. | |||
*/ | |||
public interface CIDSet { | |||
/** | |||
* Returns the original index of the glyph inside the (non-subset) font's glyph list. This | |||
* index can be used to access the character width information, for example. | |||
* @param index the subset index (character selector) to access the glyph | |||
* @return the original index (or -1 if no glyph index is available for the subset index) | |||
*/ | |||
int getOriginalGlyphIndex(int index); | |||
/** | |||
* Returns the Unicode value for a subset index (character selector). If there's no such | |||
* Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned. | |||
* @param subsetIndex the subset index (character selector) | |||
* @return the Unicode value or "NOT A CHARACTER" (0xFFFF) | |||
*/ | |||
char getUnicode(int index); | |||
/** | |||
* Maps a character to a character selector for a font subset. If the character isn't in the | |||
* subset, yet, it is added and a new character selector returned. Otherwise, the already | |||
* allocated character selector is returned from the existing map/subset. | |||
* @param glyphIndex the glyph index of the character | |||
* @param unicode the Unicode index of the character | |||
* @return the subset index | |||
*/ | |||
int mapChar(int glyphIndex, char unicode); | |||
/** | |||
* Returns an unmodifiable Map of the font subset. It maps from glyph index to | |||
* character selector (i.e. the subset index in this case). | |||
* @return Map Map<Integer, Integer> of the font subset | |||
*/ | |||
Map<Integer, Integer> getGlyphs(); | |||
/** | |||
* Returns a char array containing all Unicode characters that are in the subset. | |||
* @return a char array with all used Unicode characters | |||
*/ | |||
char[] getChars(); | |||
/** | |||
* Returns the number of glyphs in the subset. | |||
* @return the number of glyphs in the subset | |||
*/ | |||
int getNumberOfGlyphs(); | |||
/** | |||
* Returns a BitSet with bits set for each available glyph index in the subset. | |||
* @return a BitSet indicating available glyph indices | |||
*/ | |||
BitSet getGlyphIndices(); | |||
/** | |||
* Return the array of widths. | |||
* <p> | |||
* This is used to get an array for inserting in an output format. | |||
* It should not be used for lookup. | |||
* @return an array of widths | |||
*/ | |||
int[] getWidths(); | |||
} |
@@ -26,18 +26,16 @@ import java.util.Map; | |||
import org.apache.fop.util.CharUtilities; | |||
//Naming: | |||
//glyph index: original index of the glyph in the non-subset font (!= unicode index) | |||
//character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For | |||
// non-subset fonts, this is the same as the glyph index. | |||
//Unicode index: The Unicode codepoint of a character. | |||
//Glyph name: the Adobe glyph name (as found in Glyphs.java) | |||
/** | |||
* Keeps track of the glyphs used in a document. This information is later used to build | |||
* a subset of a font. | |||
* Provides methods to get font information. | |||
* Naming: | |||
* glyph index: original index of the glyph in the non-subset font (!= unicode index) | |||
* character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset | |||
* fonts, this is the same as the glyph index. | |||
* Unicode index: The Unicode codepoint of a character. | |||
* Glyph name: the Adobe glyph name (as found in Glyphs.java) | |||
*/ | |||
public class CIDSubset { | |||
public class CIDSubset implements CIDSet { | |||
/** | |||
* usedGlyphs contains orginal, new glyph index (glyph index -> char selector) | |||
@@ -48,51 +46,36 @@ public class CIDSubset { | |||
* usedGlyphsIndex contains new glyph, original index (char selector -> glyph index) | |||
*/ | |||
private Map<Integer, Integer> usedGlyphsIndex = new HashMap<Integer, Integer>(); | |||
private int usedGlyphsCount = 0; | |||
private int usedGlyphsCount; | |||
/** | |||
* usedCharsIndex contains new glyph, original char (char selector -> Unicode) | |||
*/ | |||
private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>(); | |||
/** | |||
* Default constructor. | |||
*/ | |||
public CIDSubset() { | |||
} | |||
private final MultiByteFont font; | |||
/** | |||
* Adds the first glyph which is reserved for .notdef for all CID subsets. | |||
*/ | |||
public void setupFirstGlyph() { | |||
usedGlyphs.put(Integer.valueOf(0), Integer.valueOf(0)); | |||
usedGlyphsIndex.put(Integer.valueOf(0), Integer.valueOf(0)); | |||
public CIDSubset(MultiByteFont mbf) { | |||
font = mbf; | |||
// The zeroth value is reserved for .notdef | |||
usedGlyphs.put(0, 0); | |||
usedGlyphsIndex.put(0, 0); | |||
usedGlyphsCount++; | |||
} | |||
/** | |||
* Returns the original index of the glyph inside the (non-subset) font's glyph list. This | |||
* index can be used to access the character width information, for example. | |||
* @param subsetIndex the subset index (character selector) to access the glyph | |||
* @return the original index (or -1 if no glyph index is available for the subset index) | |||
*/ | |||
public int getGlyphIndexForSubsetIndex(int subsetIndex) { | |||
Integer glyphIndex = usedGlyphsIndex.get(Integer.valueOf(subsetIndex)); | |||
/** {@inheritDoc} */ | |||
public int getOriginalGlyphIndex(int index) { | |||
Integer glyphIndex = usedGlyphsIndex.get(index); | |||
if (glyphIndex != null) { | |||
return glyphIndex.intValue(); | |||
return glyphIndex; | |||
} else { | |||
return -1; | |||
} | |||
} | |||
/** | |||
* Returns the Unicode value for a subset index (character selector). If there's no such | |||
* Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned. | |||
* @param subsetIndex the subset index (character selector) | |||
* @return the Unicode value or "NOT A CHARACTER" (0xFFFF) | |||
*/ | |||
public char getUnicodeForSubsetIndex(int subsetIndex) { | |||
Character mapValue = usedCharsIndex.get(Integer.valueOf(subsetIndex)); | |||
/** {@inheritDoc} */ | |||
public char getUnicode(int index) { | |||
Character mapValue = usedCharsIndex.get(index); | |||
if (mapValue != null) { | |||
return mapValue.charValue(); | |||
} else { | |||
@@ -100,72 +83,60 @@ public class CIDSubset { | |||
} | |||
} | |||
/** | |||
* Maps a character to a character selector for a font subset. If the character isn't in the | |||
* subset, yet, it is added and a new character selector returned. Otherwise, the already | |||
* allocated character selector is returned from the existing map/subset. | |||
* @param glyphIndex the glyph index of the character | |||
* @param unicode the Unicode index of the character | |||
* @return the subset index | |||
*/ | |||
public int mapSubsetChar(int glyphIndex, char unicode) { | |||
/** {@inheritDoc} */ | |||
public int mapChar(int glyphIndex, char unicode) { | |||
// Reencode to a new subset font or get the reencoded value | |||
// IOW, accumulate the accessed characters and build a character map for them | |||
Integer subsetCharSelector = usedGlyphs.get(Integer.valueOf(glyphIndex)); | |||
Integer subsetCharSelector = usedGlyphs.get(glyphIndex); | |||
if (subsetCharSelector == null) { | |||
int selector = usedGlyphsCount; | |||
usedGlyphs.put(Integer.valueOf(glyphIndex), | |||
Integer.valueOf(selector)); | |||
usedGlyphsIndex.put(Integer.valueOf(selector), | |||
Integer.valueOf(glyphIndex)); | |||
usedCharsIndex.put(Integer.valueOf(selector), | |||
Character.valueOf(unicode)); | |||
usedGlyphs.put(glyphIndex, selector); | |||
usedGlyphsIndex.put(selector, glyphIndex); | |||
usedCharsIndex.put(selector, unicode); | |||
usedGlyphsCount++; | |||
return selector; | |||
} else { | |||
return subsetCharSelector.intValue(); | |||
return subsetCharSelector; | |||
} | |||
} | |||
/** | |||
* Returns an unmodifiable Map of the font subset. It maps from glyph index to | |||
* character selector (i.e. the subset index in this case). | |||
* @return Map Map<Integer, Integer> of the font subset | |||
*/ | |||
public Map<Integer, Integer> getSubsetGlyphs() { | |||
/** {@inheritDoc} */ | |||
public Map<Integer, Integer> getGlyphs() { | |||
return Collections.unmodifiableMap(this.usedGlyphs); | |||
} | |||
/** | |||
* Returns a char array containing all Unicode characters that are in the subset. | |||
* @return a char array with all used Unicode characters | |||
*/ | |||
public char[] getSubsetChars() { | |||
/** {@inheritDoc} */ | |||
public char[] getChars() { | |||
char[] charArray = new char[usedGlyphsCount]; | |||
for (int i = 0; i < usedGlyphsCount; i++) { | |||
charArray[i] = getUnicodeForSubsetIndex(i); | |||
charArray[i] = getUnicode(i); | |||
} | |||
return charArray; | |||
} | |||
/** | |||
* Returns the number of glyphs in the subset. | |||
* @return the number of glyphs in the subset | |||
*/ | |||
public int getSubsetSize() { | |||
/** {@inheritDoc} */ | |||
public int getNumberOfGlyphs() { | |||
return this.usedGlyphsCount; | |||
} | |||
/** | |||
* Returns a BitSet with bits set for each available glyph index in the subset. | |||
* @return a BitSet indicating available glyph indices | |||
*/ | |||
public BitSet getGlyphIndexBitSet() { | |||
/** {@inheritDoc} */ | |||
public BitSet getGlyphIndices() { | |||
BitSet bitset = new BitSet(); | |||
for (Integer cid : usedGlyphs.keySet()) { | |||
bitset.set(cid.intValue()); | |||
bitset.set(cid); | |||
} | |||
return bitset; | |||
} | |||
/** {@inheritDoc} */ | |||
public int[] getWidths() { | |||
int[] widths = font.getWidths(); | |||
int[] tmpWidth = new int[getNumberOfGlyphs()]; | |||
for (int i = 0, c = getNumberOfGlyphs(); i < c; i++) { | |||
int nwx = Math.max(0, getOriginalGlyphIndex(i)); | |||
tmpWidth[i] = widths[nwx]; | |||
} | |||
return tmpWidth; | |||
} | |||
} |
@@ -157,7 +157,7 @@ public class FontReader extends DefaultHandler { | |||
throws SAXException { | |||
if (localName.equals("font-metrics")) { | |||
if ("TYPE0".equals(attributes.getValue("type"))) { | |||
multiFont = new MultiByteFont(resourceResolver); | |||
multiFont = new MultiByteFont(resourceResolver, EmbeddingMode.AUTO); | |||
returnFont = multiFont; | |||
isCID = true; | |||
TTFReader.checkMetricsVersion(attributes); |
@@ -438,6 +438,9 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, | |||
*/ | |||
public boolean isSubsetEmbedded() { | |||
load(true); | |||
if (realFont.isMultiByte() && this.embeddingMode == EmbeddingMode.FULL) { | |||
return false; | |||
} | |||
return realFont.isMultiByte(); | |||
} | |||
@@ -21,6 +21,7 @@ package org.apache.fop.fonts; | |||
import java.nio.CharBuffer; | |||
import java.nio.IntBuffer; | |||
import java.util.BitSet; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
@@ -44,13 +45,13 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
private static final Log log // CSOK: ConstantNameCheck | |||
= LogFactory.getLog(MultiByteFont.class); | |||
private String ttcName = null; | |||
private String ttcName; | |||
private String encoding = "Identity-H"; | |||
private int defaultWidth = 0; | |||
private int defaultWidth; | |||
private CIDFontType cidType = CIDFontType.CIDTYPE2; | |||
private CIDSubset subset = new CIDSubset(); | |||
private final CIDSet cidSet; | |||
/* advanced typographic support */ | |||
private GlyphDefinitionTable gdef; | |||
@@ -69,10 +70,15 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
/** | |||
* Default constructor | |||
*/ | |||
public MultiByteFont(InternalResourceResolver resourceResolver) { | |||
public MultiByteFont(InternalResourceResolver resourceResolver, EmbeddingMode embeddingMode) { | |||
super(resourceResolver); | |||
subset.setupFirstGlyph(); | |||
setFontType(FontType.TYPE0); | |||
setEmbeddingMode(embeddingMode); | |||
if (embeddingMode != EmbeddingMode.FULL) { | |||
cidSet = new CIDSubset(this); | |||
} else { | |||
cidSet = new CIDFull(this); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -129,13 +135,16 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
} | |||
public boolean isSubsetEmbedded() { | |||
if (getEmbeddingMode() == EmbeddingMode.FULL) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public CIDSubset getCIDSubset() { | |||
return this.subset; | |||
public CIDSet getCIDSet() { | |||
return this.cidSet; | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -147,7 +156,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
/** {@inheritDoc} */ | |||
public int getWidth(int i, int size) { | |||
if (isEmbeddable()) { | |||
int glyphIndex = subset.getGlyphIndexForSubsetIndex(i); | |||
int glyphIndex = cidSet.getOriginalGlyphIndex(i); | |||
return size * width[glyphIndex]; | |||
} else { | |||
return size * width[i]; | |||
@@ -283,9 +292,39 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
glyphIndex = findGlyphIndex(Typeface.NOT_FOUND); | |||
} | |||
if (isEmbeddable()) { | |||
glyphIndex = subset.mapSubsetChar(glyphIndex, c); | |||
glyphIndex = cidSet.mapChar(glyphIndex, c); | |||
} | |||
return (char)glyphIndex; | |||
return (char) glyphIndex; | |||
} | |||
protected BitSet getGlyphIndices() { | |||
BitSet bitset = new BitSet(); | |||
bitset.set(0); | |||
bitset.set(1); | |||
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(); | |||
while (start++ < end + 1) { | |||
bitset.set(glyphIndex++); | |||
} | |||
} | |||
return bitset; | |||
} | |||
protected char[] getChars() { | |||
// the width array is set when the font is built | |||
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(); | |||
while (start < end + 1) { | |||
chars[glyphIndex++] = (char) start++; | |||
} | |||
} | |||
return chars; | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -331,15 +370,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
* @return Map Map of used Glyphs | |||
*/ | |||
public Map<Integer, Integer> getUsedGlyphs() { | |||
return subset.getSubsetGlyphs(); | |||
} | |||
/** @return an array of the chars used */ | |||
public char[] getCharsUsed() { | |||
if (!isEmbeddable()) { | |||
return null; | |||
} | |||
return subset.getSubsetChars(); | |||
return cidSet.getGlyphs(); | |||
} | |||
/** |
@@ -127,7 +127,7 @@ public class TTFFontLoader extends FontLoader { | |||
} | |||
if (isCid) { | |||
multiFont = new MultiByteFont(resourceResolver); | |||
multiFont = new MultiByteFont(resourceResolver, embeddingMode); | |||
returnFont = multiFont; | |||
multiFont.setTTCName(ttcFontName); | |||
} else { |
@@ -44,9 +44,9 @@ import org.apache.xmlgraphics.java2d.color.NamedColorSpace; | |||
import org.apache.xmlgraphics.xmp.Metadata; | |||
import org.apache.fop.fonts.CIDFont; | |||
import org.apache.fop.fonts.CIDSubset; | |||
import org.apache.fop.fonts.CodePointMapping; | |||
import org.apache.fop.fonts.CustomFont; | |||
import org.apache.fop.fonts.EmbeddingMode; | |||
import org.apache.fop.fonts.FontDescriptor; | |||
import org.apache.fop.fonts.FontMetrics; | |||
import org.apache.fop.fonts.FontType; | |||
@@ -1369,23 +1369,14 @@ public class PDFFactory { | |||
} else { | |||
cidMetrics = (CIDFont)metrics; | |||
} | |||
PDFCIDSystemInfo sysInfo | |||
= new PDFCIDSystemInfo(cidMetrics.getRegistry(), | |||
cidMetrics.getOrdering(), | |||
cidMetrics.getSupplement()); | |||
PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, | |||
cidMetrics.getCIDType(), | |||
cidMetrics.getDefaultWidth(), | |||
getSubsetWidths(cidMetrics), sysInfo, | |||
(PDFCIDFontDescriptor)pdfdesc); | |||
PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(), | |||
cidMetrics.getOrdering(), cidMetrics.getSupplement()); | |||
PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(), | |||
cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo, | |||
(PDFCIDFontDescriptor) pdfdesc); | |||
getDocument().registerObject(cidFont); | |||
PDFCMap cmap = new PDFToUnicodeCMap( | |||
cidMetrics.getCIDSubset().getSubsetChars(), | |||
"fop-ucs-H", | |||
new PDFCIDSystemInfo("Adobe", | |||
"Identity", | |||
0), false); | |||
PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H", | |||
new PDFCIDSystemInfo("Adobe", "Identity", 0), false); | |||
getDocument().registerObject(cmap); | |||
((PDFFontType0)font).setCMAP(cmap); | |||
((PDFFontType0)font).setDescendantFonts(cidFont); | |||
@@ -1476,23 +1467,11 @@ public class PDFFactory { | |||
return PDFEncoding.createPDFEncoding(encoding, fontName); | |||
} | |||
/** | |||
* Creates and returns a width array with the widths of all the characters in the subset. | |||
* @param cidFont the font | |||
* @return the width array | |||
*/ | |||
public PDFWArray getSubsetWidths(CIDFont cidFont) { | |||
private PDFWArray getFontWidths(CIDFont cidFont) { | |||
// Create widths for reencoded chars | |||
PDFWArray warray = new PDFWArray(); | |||
int[] widths = cidFont.getWidths(); | |||
CIDSubset subset = cidFont.getCIDSubset(); | |||
int[] tmpWidth = new int[subset.getSubsetSize()]; | |||
for (int i = 0, c = subset.getSubsetSize(); i < c; i++) { | |||
int nwx = Math.max(0, subset.getGlyphIndexForSubsetIndex(i)); | |||
tmpWidth[i] = widths[nwx]; | |||
} | |||
warray.addEntry(0, tmpWidth); | |||
int[] widths = cidFont.getCIDSet().getWidths(); | |||
warray.addEntry(0, widths); | |||
return warray; | |||
} | |||
@@ -1560,13 +1539,13 @@ public class PDFFactory { | |||
} | |||
private void buildCIDSet(PDFFontDescriptor descriptor, CIDFont cidFont) { | |||
BitSet cidSubset = cidFont.getCIDSubset().getGlyphIndexBitSet(); | |||
PDFStream cidSet = makeStream(null, true); | |||
ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSubset.length() / 8 + 1); | |||
BitSet cidSet = cidFont.getCIDSet().getGlyphIndices(); | |||
PDFStream pdfStream = makeStream(null, true); | |||
ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSet.length() / 8 + 1); | |||
int value = 0; | |||
for (int i = 0, c = cidSubset.length(); i < c; i++) { | |||
for (int i = 0, c = cidSet.length(); i < c; i++) { | |||
int shift = i % 8; | |||
boolean b = cidSubset.get(i); | |||
boolean b = cidSet.get(i); | |||
if (b) { | |||
value |= 1 << 7 - shift; | |||
} | |||
@@ -1577,8 +1556,8 @@ public class PDFFactory { | |||
} | |||
baout.write(value); | |||
try { | |||
cidSet.setData(baout.toByteArray()); | |||
descriptor.setCIDSet(cidSet); | |||
pdfStream.setData(baout.toByteArray()); | |||
descriptor.setCIDSet(pdfStream); | |||
} catch (IOException ioe) { | |||
log.error( | |||
"Failed to write CIDSet [" + cidFont + "] " | |||
@@ -1609,14 +1588,16 @@ public class PDFFactory { | |||
if (desc.getFontType() == FontType.TYPE0) { | |||
MultiByteFont mbfont = (MultiByteFont) font; | |||
FontFileReader reader = new FontFileReader(in); | |||
TTFSubSetFile subset = new TTFSubSetFile(); | |||
subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs()); | |||
byte[] subsetFont = subset.getFontSubset(); | |||
// Only TrueType CID fonts are supported now | |||
embeddedFont = new PDFTTFStream(subsetFont.length); | |||
((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length); | |||
byte[] fontBytes; | |||
if (font.getEmbeddingMode() == EmbeddingMode.FULL) { | |||
fontBytes = reader.getAllBytes(); | |||
} else { | |||
TTFSubSetFile ttfFile = new TTFSubSetFile(); | |||
ttfFile.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs()); | |||
fontBytes = ttfFile.getFontSubset(); | |||
} | |||
embeddedFont = new PDFTTFStream(fontBytes.length); | |||
((PDFTTFStream) embeddedFont).setData(fontBytes, fontBytes.length); | |||
} else if (desc.getFontType() == FontType.TYPE1) { | |||
PFBParser parser = new PFBParser(); | |||
PFBData pfb = parser.parsePFB(in); |
@@ -24,7 +24,6 @@ import org.apache.xmlgraphics.image.writer.ResolutionUnit; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
/** |
@@ -38,7 +38,7 @@ import org.apache.xmlgraphics.ps.dsc.ResourceTracker; | |||
import org.apache.fop.fonts.Base14Font; | |||
import org.apache.fop.fonts.CIDFontType; | |||
import org.apache.fop.fonts.CIDSubset; | |||
import org.apache.fop.fonts.CIDSet; | |||
import org.apache.fop.fonts.CMapSegment; | |||
import org.apache.fop.fonts.CustomFont; | |||
import org.apache.fop.fonts.EmbeddingMode; | |||
@@ -457,15 +457,17 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { | |||
// TODO /FontInfo | |||
gen.write("/CIDCount "); | |||
CIDSubset cidSubset = font.getCIDSubset(); | |||
int subsetSize = cidSubset.getSubsetSize(); | |||
gen.write(subsetSize); | |||
CIDSet cidSet = font.getCIDSet(); | |||
int numberOfGlyphs = cidSet.getNumberOfGlyphs(); | |||
gen.write(numberOfGlyphs); | |||
gen.writeln(" def"); | |||
gen.writeln("/GDBytes 2 def"); // TODO always 2? | |||
gen.writeln("/CIDMap [<"); | |||
int colCount = 0; | |||
int lineCount = 1; | |||
for (int cid = 0; cid < subsetSize; cid++) { | |||
int nextBitSet = 0; | |||
int previousBitSet = 0; | |||
for (int cid = 0; cid < numberOfGlyphs; cid++) { | |||
if (colCount++ == 20) { | |||
gen.newLine(); | |||
colCount = 1; | |||
@@ -478,7 +480,23 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { | |||
if (font.getEmbeddingMode() != EmbeddingMode.FULL) { | |||
gid = HexEncoder.encode(cid, 4); | |||
} else { | |||
gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4); | |||
previousBitSet = nextBitSet; | |||
nextBitSet = cidSet.getGlyphIndices().nextSetBit(nextBitSet); | |||
while (previousBitSet++ < nextBitSet) { | |||
// if there are gaps in the indices we pad them with zeros | |||
gen.write("0000"); | |||
cid++; | |||
if (colCount++ == 20) { | |||
gen.newLine(); | |||
colCount = 1; | |||
if (lineCount++ == 800) { | |||
gen.writeln("> <"); | |||
lineCount = 1; | |||
} | |||
} | |||
} | |||
gid = HexEncoder.encode(nextBitSet, 4); | |||
nextBitSet++; | |||
} | |||
gen.write(gid); | |||
} |
@@ -62,6 +62,9 @@ | |||
documents. Example: the fix of marks layering will be such a case when it's done. | |||
--> | |||
<release version="FOP Trunk" date="TBD"> | |||
<action context="Fonts" dev="MH" type="add" fixes-bug="53868" importance="low" due-to="Luis Bernardo"> | |||
Full font embedding in PDF | |||
</action> | |||
<action context="Renderers" dev="PH" type="add" fixes-bug="53865" importance="low"> | |||
Added configuration for RowPerStrip configuration in the Tiff renderer. | |||
RowsPerStrip can be configured to 1 or to the total # of rows. |
@@ -0,0 +1,120 @@ | |||
/* | |||
* 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.fonts; | |||
import java.util.BitSet; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import org.apache.fop.util.CharUtilities; | |||
public class CIDFullTestCase { | |||
private CIDFull cidFull; | |||
private MultiByteFont mbFont; | |||
private BitSet bs; | |||
private char[] chars; | |||
private int[] widths; | |||
private Map<Integer, Integer> glyphs; | |||
@Before | |||
public void setup() { | |||
bs = new BitSet(); | |||
glyphs = new HashMap<Integer, Integer>(); | |||
chars = new char[18]; | |||
widths = new int[18]; | |||
int i = 0; | |||
for (int j = 0; j < 20; j++) { | |||
if (j == 10 || j == 11) { | |||
continue; | |||
} | |||
bs.set(j); | |||
glyphs.put(Integer.valueOf(j), Integer.valueOf(j)); | |||
chars[i] = (char) j; | |||
widths[i] = 100; | |||
i++; | |||
} | |||
mbFont = mock(MultiByteFont.class); | |||
when(mbFont.getGlyphIndices()).thenReturn(bs); | |||
when(mbFont.getChars()).thenReturn(chars); | |||
when(mbFont.getWidths()).thenReturn(widths); | |||
cidFull = new CIDFull(mbFont); | |||
} | |||
@Test | |||
public void testGetOriginalGlyphIndex() { | |||
// index 5 exists | |||
assertEquals(cidFull.getOriginalGlyphIndex(5), 5); | |||
} | |||
@Test | |||
public void testGetUnicode() { | |||
// index 9 exists | |||
assertEquals(cidFull.getUnicode(9), (char) 9); | |||
// index 10 does not | |||
assertEquals(cidFull.getUnicode(10), CharUtilities.NOT_A_CHARACTER); | |||
} | |||
@Test | |||
public void testMapChar() { | |||
// index 9 exists | |||
char c = 'a'; | |||
assertEquals(cidFull.mapChar(9, c), (char) 9); | |||
} | |||
@Test | |||
public void testGetGlyphs() { | |||
Map<Integer, Integer> fontGlyphs = cidFull.getGlyphs(); | |||
for (Integer key : fontGlyphs.keySet()) { | |||
assertEquals(fontGlyphs.get(key), glyphs.get(key)); | |||
} | |||
assertTrue(fontGlyphs.size() == glyphs.size()); | |||
} | |||
@Test | |||
public void testGetChars() { | |||
assertArrayEquals(cidFull.getChars(), chars); | |||
} | |||
@Test | |||
public void testGetNumberOfGlyphs() { | |||
assertTrue(cidFull.getNumberOfGlyphs() == 20); | |||
} | |||
@Test | |||
public void testGetGlyphIndices() { | |||
assertEquals(bs, cidFull.getGlyphIndices()); | |||
} | |||
@Test | |||
public void testGetWidths() { | |||
assertArrayEquals(cidFull.getWidths(), widths); | |||
} | |||
} |
@@ -24,14 +24,16 @@ import java.net.URI; | |||
import org.junit.Test; | |||
import static org.junit.Assert.assertEquals; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolverFactory; | |||
import org.apache.fop.fonts.CIDSet; | |||
import org.apache.fop.fonts.CIDSubset; | |||
import org.apache.fop.fonts.EmbeddingMode; | |||
import org.apache.fop.fonts.MultiByteFont; | |||
import static org.junit.Assert.assertEquals; | |||
/** | |||
* Test case for {@link PDFFactory}. | |||
*/ | |||
@@ -45,7 +47,7 @@ public class PDFFactoryTestCase { | |||
public void testSubsetFontNamePrefix() { | |||
class MockedFont extends MultiByteFont { | |||
public MockedFont(InternalResourceResolver resolver) { | |||
super(resolver); | |||
super(resolver, EmbeddingMode.AUTO); | |||
} | |||
@Override | |||
@@ -54,8 +56,8 @@ public class PDFFactoryTestCase { | |||
} | |||
@Override | |||
public CIDSubset getCIDSubset() { | |||
return new CIDSubset(); | |||
public CIDSet getCIDSet() { | |||
return new CIDSubset(this); | |||
} | |||
} | |||
PDFDocument doc = new PDFDocument("Test"); |