Просмотр исходного кода

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 лет назад
Родитель
Сommit
ccd2678cd0

+ 2
- 2
src/java/org/apache/fop/fonts/CIDFont.java Просмотреть файл

public abstract class CIDFont extends CustomFont { public abstract class CIDFont extends CustomFont {


/** Contains the character widths for all characters in the font */ /** 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 * @param resourceResolver the URI resolver for controlling file access
* Returns the subset information for this font. * Returns the subset information for this font.
* @return the subset information * @return the subset information
*/ */
public abstract CIDSubset getCIDSubset();
public abstract CIDSet getCIDSet();


// ---- Optional ---- // ---- Optional ----
/** /**

+ 113
- 0
src/java/org/apache/fop/fonts/CIDFull.java Просмотреть файл

/*
* 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 Просмотреть файл

/*
* 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 Просмотреть файл



import org.apache.fop.util.CharUtilities; 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) * usedGlyphs contains orginal, new glyph index (glyph index -> char selector)
* usedGlyphsIndex contains new glyph, original index (char selector -> glyph index) * usedGlyphsIndex contains new glyph, original index (char selector -> glyph index)
*/ */
private Map<Integer, Integer> usedGlyphsIndex = new HashMap<Integer, Integer>(); 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) * usedCharsIndex contains new glyph, original char (char selector -> Unicode)
*/ */
private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>(); 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++; 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) { if (glyphIndex != null) {
return glyphIndex.intValue();
return glyphIndex;
} else { } else {
return -1; 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) { if (mapValue != null) {
return mapValue.charValue(); return mapValue.charValue();
} else { } else {
} }
} }


/**
* 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 // Reencode to a new subset font or get the reencoded value
// IOW, accumulate the accessed characters and build a character map for them // 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) { if (subsetCharSelector == null) {
int selector = usedGlyphsCount; 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++; usedGlyphsCount++;
return selector; return selector;
} else { } 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); 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]; char[] charArray = new char[usedGlyphsCount];
for (int i = 0; i < usedGlyphsCount; i++) { for (int i = 0; i < usedGlyphsCount; i++) {
charArray[i] = getUnicodeForSubsetIndex(i);
charArray[i] = getUnicode(i);
} }
return charArray; 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; 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(); BitSet bitset = new BitSet();
for (Integer cid : usedGlyphs.keySet()) { for (Integer cid : usedGlyphs.keySet()) {
bitset.set(cid.intValue());
bitset.set(cid);
} }
return bitset; 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 Просмотреть файл

throws SAXException { throws SAXException {
if (localName.equals("font-metrics")) { if (localName.equals("font-metrics")) {
if ("TYPE0".equals(attributes.getValue("type"))) { if ("TYPE0".equals(attributes.getValue("type"))) {
multiFont = new MultiByteFont(resourceResolver);
multiFont = new MultiByteFont(resourceResolver, EmbeddingMode.AUTO);
returnFont = multiFont; returnFont = multiFont;
isCID = true; isCID = true;
TTFReader.checkMetricsVersion(attributes); TTFReader.checkMetricsVersion(attributes);

+ 3
- 0
src/java/org/apache/fop/fonts/LazyFont.java Просмотреть файл

*/ */
public boolean isSubsetEmbedded() { public boolean isSubsetEmbedded() {
load(true); load(true);
if (realFont.isMultiByte() && this.embeddingMode == EmbeddingMode.FULL) {
return false;
}
return realFont.isMultiByte(); return realFont.isMultiByte();
} }



+ 50
- 19
src/java/org/apache/fop/fonts/MultiByteFont.java Просмотреть файл



import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.BitSet;
import java.util.Map; import java.util.Map;


import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
private static final Log log // CSOK: ConstantNameCheck private static final Log log // CSOK: ConstantNameCheck
= LogFactory.getLog(MultiByteFont.class); = LogFactory.getLog(MultiByteFont.class);


private String ttcName = null;
private String ttcName;
private String encoding = "Identity-H"; private String encoding = "Identity-H";


private int defaultWidth = 0;
private int defaultWidth;
private CIDFontType cidType = CIDFontType.CIDTYPE2; private CIDFontType cidType = CIDFontType.CIDTYPE2;


private CIDSubset subset = new CIDSubset();
private final CIDSet cidSet;


/* advanced typographic support */ /* advanced typographic support */
private GlyphDefinitionTable gdef; private GlyphDefinitionTable gdef;
/** /**
* Default constructor * Default constructor
*/ */
public MultiByteFont(InternalResourceResolver resourceResolver) {
public MultiByteFont(InternalResourceResolver resourceResolver, EmbeddingMode embeddingMode) {
super(resourceResolver); super(resourceResolver);
subset.setupFirstGlyph();
setFontType(FontType.TYPE0); setFontType(FontType.TYPE0);
setEmbeddingMode(embeddingMode);
if (embeddingMode != EmbeddingMode.FULL) {
cidSet = new CIDSubset(this);
} else {
cidSet = new CIDFull(this);
}
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
} }


public boolean isSubsetEmbedded() { public boolean isSubsetEmbedded() {
if (getEmbeddingMode() == EmbeddingMode.FULL) {
return false;
}
return true; return true;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public CIDSubset getCIDSubset() {
return this.subset;
public CIDSet getCIDSet() {
return this.cidSet;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
/** {@inheritDoc} */ /** {@inheritDoc} */
public int getWidth(int i, int size) { public int getWidth(int i, int size) {
if (isEmbeddable()) { if (isEmbeddable()) {
int glyphIndex = subset.getGlyphIndexForSubsetIndex(i);
int glyphIndex = cidSet.getOriginalGlyphIndex(i);
return size * width[glyphIndex]; return size * width[glyphIndex];
} else { } else {
return size * width[i]; return size * width[i];
glyphIndex = findGlyphIndex(Typeface.NOT_FOUND); glyphIndex = findGlyphIndex(Typeface.NOT_FOUND);
} }
if (isEmbeddable()) { 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} */ /** {@inheritDoc} */
* @return Map Map of used Glyphs * @return Map Map of used Glyphs
*/ */
public Map<Integer, Integer> getUsedGlyphs() { 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 Просмотреть файл

} }


if (isCid) { if (isCid) {
multiFont = new MultiByteFont(resourceResolver);
multiFont = new MultiByteFont(resourceResolver, embeddingMode);
returnFont = multiFont; returnFont = multiFont;
multiFont.setTTCName(ttcFontName); multiFont.setTTCName(ttcFontName);
} else { } else {

+ 28
- 47
src/java/org/apache/fop/pdf/PDFFactory.java Просмотреть файл

import org.apache.xmlgraphics.xmp.Metadata; import org.apache.xmlgraphics.xmp.Metadata;


import org.apache.fop.fonts.CIDFont; import org.apache.fop.fonts.CIDFont;
import org.apache.fop.fonts.CIDSubset;
import org.apache.fop.fonts.CodePointMapping; import org.apache.fop.fonts.CodePointMapping;
import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.FontDescriptor; import org.apache.fop.fonts.FontDescriptor;
import org.apache.fop.fonts.FontMetrics; import org.apache.fop.fonts.FontMetrics;
import org.apache.fop.fonts.FontType; import org.apache.fop.fonts.FontType;
} else { } else {
cidMetrics = (CIDFont)metrics; 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); 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); getDocument().registerObject(cmap);
((PDFFontType0)font).setCMAP(cmap); ((PDFFontType0)font).setCMAP(cmap);
((PDFFontType0)font).setDescendantFonts(cidFont); ((PDFFontType0)font).setDescendantFonts(cidFont);
return PDFEncoding.createPDFEncoding(encoding, fontName); 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 // Create widths for reencoded chars
PDFWArray warray = new PDFWArray(); 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; return warray;
} }


} }


private void buildCIDSet(PDFFontDescriptor descriptor, CIDFont cidFont) { 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; 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; int shift = i % 8;
boolean b = cidSubset.get(i);
boolean b = cidSet.get(i);
if (b) { if (b) {
value |= 1 << 7 - shift; value |= 1 << 7 - shift;
} }
} }
baout.write(value); baout.write(value);
try { try {
cidSet.setData(baout.toByteArray());
descriptor.setCIDSet(cidSet);
pdfStream.setData(baout.toByteArray());
descriptor.setCIDSet(pdfStream);
} catch (IOException ioe) { } catch (IOException ioe) {
log.error( log.error(
"Failed to write CIDSet [" + cidFont + "] " "Failed to write CIDSet [" + cidFont + "] "
if (desc.getFontType() == FontType.TYPE0) { if (desc.getFontType() == FontType.TYPE0) {
MultiByteFont mbfont = (MultiByteFont) font; MultiByteFont mbfont = (MultiByteFont) font;
FontFileReader reader = new FontFileReader(in); 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) { } else if (desc.getFontType() == FontType.TYPE1) {
PFBParser parser = new PFBParser(); PFBParser parser = new PFBParser();
PFBData pfb = parser.parsePFB(in); PFBData pfb = parser.parsePFB(in);

+ 0
- 1
src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java Просмотреть файл

import org.apache.fop.apps.MimeConstants; import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser; import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser;
import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;


/** /**

+ 24
- 6
src/java/org/apache/fop/render/ps/PSFontUtils.java Просмотреть файл



import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.Base14Font;
import org.apache.fop.fonts.CIDFontType; 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.CMapSegment;
import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.EmbeddingMode;
// TODO /FontInfo // TODO /FontInfo


gen.write("/CIDCount "); 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(" def");
gen.writeln("/GDBytes 2 def"); // TODO always 2? gen.writeln("/GDBytes 2 def"); // TODO always 2?
gen.writeln("/CIDMap [<"); gen.writeln("/CIDMap [<");
int colCount = 0; int colCount = 0;
int lineCount = 1; 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) { if (colCount++ == 20) {
gen.newLine(); gen.newLine();
colCount = 1; colCount = 1;
if (font.getEmbeddingMode() != EmbeddingMode.FULL) { if (font.getEmbeddingMode() != EmbeddingMode.FULL) {
gid = HexEncoder.encode(cid, 4); gid = HexEncoder.encode(cid, 4);
} else { } 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); gen.write(gid);
} }

+ 3
- 0
status.xml Просмотреть файл

documents. Example: the fix of marks layering will be such a case when it's done. documents. Example: the fix of marks layering will be such a case when it's done.
--> -->
<release version="FOP Trunk" date="TBD"> <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"> <action context="Renderers" dev="PH" type="add" fixes-bug="53865" importance="low">
Added configuration for RowPerStrip configuration in the Tiff renderer. Added configuration for RowPerStrip configuration in the Tiff renderer.
RowsPerStrip can be configured to 1 or to the total # of rows. RowsPerStrip can be configured to 1 or to the total # of rows.

+ 120
- 0
test/java/org/apache/fop/fonts/CIDFullTestCase.java Просмотреть файл

/*
* 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 Просмотреть файл



import org.junit.Test; import org.junit.Test;


import static org.junit.Assert.assertEquals;

import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.ResourceResolver; import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.CIDSet;
import org.apache.fop.fonts.CIDSubset; import org.apache.fop.fonts.CIDSubset;
import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.fonts.MultiByteFont;


import static org.junit.Assert.assertEquals;

/** /**
* Test case for {@link PDFFactory}. * Test case for {@link PDFFactory}.
*/ */
public void testSubsetFontNamePrefix() { public void testSubsetFontNamePrefix() {
class MockedFont extends MultiByteFont { class MockedFont extends MultiByteFont {
public MockedFont(InternalResourceResolver resolver) { public MockedFont(InternalResourceResolver resolver) {
super(resolver);
super(resolver, EmbeddingMode.AUTO);
} }


@Override @Override
} }


@Override @Override
public CIDSubset getCIDSubset() {
return new CIDSubset();
public CIDSet getCIDSet() {
return new CIDSubset(this);
} }
} }
PDFDocument doc = new PDFDocument("Test"); PDFDocument doc = new PDFDocument("Test");

Загрузка…
Отмена
Сохранить