Browse Source

Bugzilla#53868: Full font embedding in PDF


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1384690 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Mehdi Houshmand 11 years ago
parent
commit
ccd2678cd0

+ 2
- 2
src/java/org/apache/fop/fonts/CIDFont.java View File

@@ -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 ----
/**

+ 113
- 0
src/java/org/apache/fop/fonts/CIDFull.java View File

@@ -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();
}

}

+ 90
- 0
src/java/org/apache/fop/fonts/CIDSet.java View File

@@ -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&lt;Integer, Integer&gt; 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();

}

+ 50
- 79
src/java/org/apache/fop/fonts/CIDSubset.java View File

@@ -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&lt;Integer, Integer&gt; 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;
}

}

+ 1
- 1
src/java/org/apache/fop/fonts/FontReader.java View File

@@ -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);

+ 3
- 0
src/java/org/apache/fop/fonts/LazyFont.java View File

@@ -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();
}


+ 50
- 19
src/java/org/apache/fop/fonts/MultiByteFont.java View File

@@ -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();
}

/**

+ 1
- 1
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java View File

@@ -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 {

+ 28
- 47
src/java/org/apache/fop/pdf/PDFFactory.java View File

@@ -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);

+ 0
- 1
src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java View File

@@ -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;

/**

+ 24
- 6
src/java/org/apache/fop/render/ps/PSFontUtils.java View File

@@ -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);
}

+ 3
- 0
status.xml View File

@@ -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.

+ 120
- 0
test/java/org/apache/fop/fonts/CIDFullTestCase.java View File

@@ -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);
}

}

+ 7
- 5
test/java/org/apache/fop/pdf/PDFFactoryTestCase.java View File

@@ -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");

Loading…
Cancel
Save