You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2023/07/06 06:31:37 UTC
svn commit: r1910805 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font: PDCIDFontType2.java PDTrueTypeFont.java
Author: lehmi
Date: Thu Jul 6 06:31:36 2023
New Revision: 1910805
URL: http://svn.apache.org/viewvc?rev=1910805&view=rev
Log:
PDFBOX-5634: allow OpenType fonts using CFF-bases outlines for rendering and don't replace them
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java?rev=1910805&r1=1910804&r2=1910805&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java Thu Jul 6 06:31:36 2023
@@ -19,20 +19,24 @@ package org.apache.pdfbox.pdmodel.font;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.cff.CFFFont;
import org.apache.fontbox.cff.Type2CharString;
import org.apache.fontbox.cmap.CMap;
import org.apache.fontbox.ttf.CmapLookup;
import org.apache.fontbox.ttf.GlyphData;
import org.apache.fontbox.ttf.OTFParser;
import org.apache.fontbox.ttf.OpenTypeFont;
+import org.apache.fontbox.ttf.TTFParser;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.fontbox.util.BoundingBox;
import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.io.RandomAccessRead;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.util.Matrix;
@@ -47,6 +51,7 @@ public class PDCIDFontType2 extends PDCI
private static final Log LOG = LogFactory.getLog(PDCIDFontType2.class);
private final TrueTypeFont ttf;
+ private final OpenTypeFont otf;
private final int[] cid2gid;
private final boolean isEmbedded;
private final boolean isDamaged;
@@ -83,6 +88,9 @@ public class PDCIDFontType2 extends PDCI
if (trueTypeFont != null)
{
ttf = trueTypeFont;
+ otf = trueTypeFont instanceof OpenTypeFont
+ && ((OpenTypeFont) trueTypeFont).isSupportedOTF() ? (OpenTypeFont) trueTypeFont
+ : null;
isEmbedded = true;
isDamaged = false;
}
@@ -110,16 +118,10 @@ public class PDCIDFontType2 extends PDCI
try
{
// embedded OTF or TTF
- OTFParser otfParser = new OTFParser(true);
- OpenTypeFont otf = otfParser.parse(stream.getCOSObject().createView());
- ttfFont = otf;
-
- if (otf.isPostScript())
- {
- // PDFBOX-3344 contains PostScript outlines instead of TrueType
- fontIsDamaged = true;
- LOG.warn("Found CFF/OTF but expected embedded TTF font " + fd.getFontName());
- }
+ RandomAccessRead view = stream.getCOSObject().createView();
+ TTFParser ttfParser = getParser(view, true);
+ ttfFont = ttfParser.parse(view);
+ ttfFont.close();
}
catch (IOException e)
{
@@ -134,6 +136,8 @@ public class PDCIDFontType2 extends PDCI
{
ttfFont = findFontOrSubstitute();
}
+ otf = ttfFont instanceof OpenTypeFont && ((OpenTypeFont) ttfFont).isSupportedOTF()
+ ? (OpenTypeFont) ttfFont : null;
ttf = ttfFont;
}
cmap = ttf.getUnicodeCmapLookup(false);
@@ -426,39 +430,38 @@ public class PDCIDFontType2 extends PDCI
@Override
public GeneralPath getPath(int code) throws IOException
{
- if (ttf instanceof OpenTypeFont && ((OpenTypeFont)ttf).isPostScript())
+ if (otf != null && otf.isPostScript())
{
- // we're not supposed to have CFF fonts inside PDCIDFontType2, but if we do,
- // then we treat their CIDs as GIDs, see PDFBOX-3344
- int cid = codeToGID(code);
- Type2CharString charstring = ((OpenTypeFont)ttf).getCFF().getFont().getType2CharString(cid);
- return charstring.getPath();
+ GeneralPath path = getPathFromOutlines(code);
+ return path == null ? new GeneralPath() : path;
}
- else
+ int gid = codeToGID(code);
+ GlyphData glyph = ttf.getGlyph().getGlyph(gid);
+ if (glyph != null)
{
- int gid = codeToGID(code);
- GlyphData glyph = ttf.getGlyph().getGlyph(gid);
- if (glyph != null)
- {
- return glyph.getPath();
- }
- return new GeneralPath();
+ return glyph.getPath();
}
+ return new GeneralPath();
}
@Override
public GeneralPath getNormalizedPath(int code) throws IOException
{
- int gid = codeToGID(code);
-
- GeneralPath path = getPath(code);
-
- // Acrobat only draws GID 0 for embedded CIDFonts, see PDFBOX-2372
- if (gid == 0 && !isEmbedded())
+ GeneralPath path = null;
+ if (otf != null && otf.isPostScript())
{
- path = null;
+ path = getPathFromOutlines(code);
+ }
+ else
+ {
+ int gid = codeToGID(code);
+ path = getPath(code);
+ // Acrobat only draws GID 0 for embedded CIDFonts, see PDFBOX-2372
+ if (gid == 0 && !isEmbedded())
+ {
+ path = null;
+ }
}
-
if (path == null)
{
// empty glyph (e.g. space, newline)
@@ -477,9 +480,42 @@ public class PDCIDFontType2 extends PDCI
return path;
}
+ private GeneralPath getPathFromOutlines(int code) throws IOException
+ {
+ CFFFont cffFont = otf.getCFF().getFont();
+ int gid = codeToGID(code);
+ Type2CharString type2CharString = cffFont.getType2CharString(gid);
+ return type2CharString != null ? type2CharString.getPath() : null;
+ }
+
@Override
public boolean hasGlyph(int code) throws IOException
{
return codeToGID(code) != 0;
}
+
+ private TTFParser getParser(RandomAccessRead randomAccessRead, boolean isEmbedded)
+ throws IOException
+ {
+ long startPos = randomAccessRead.getPosition();
+ byte[] tagBytes = new byte[4];
+ int remainingBytes = tagBytes.length;
+ int amountRead;
+ while ((amountRead = randomAccessRead.read(tagBytes, tagBytes.length - remainingBytes,
+ remainingBytes)) > 0)
+ {
+ remainingBytes -= amountRead;
+ }
+ randomAccessRead.seek(startPos);
+ if ("OTTO".equals(new String(tagBytes, StandardCharsets.US_ASCII)))
+ {
+ return new OTFParser(isEmbedded);
+ }
+ else
+ {
+ return new TTFParser(isEmbedded);
+ }
+ }
+
}
+
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java?rev=1910805&r1=1910804&r2=1910805&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java Thu Jul 6 06:31:36 2023
@@ -21,15 +21,20 @@ import java.awt.geom.GeneralPath;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fontbox.FontBoxFont;
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.Type2CharString;
import org.apache.fontbox.ttf.CmapSubtable;
import org.apache.fontbox.ttf.CmapTable;
import org.apache.fontbox.ttf.GlyphData;
import org.apache.fontbox.ttf.GlyphTable;
+import org.apache.fontbox.ttf.OTFParser;
+import org.apache.fontbox.ttf.OpenTypeFont;
import org.apache.fontbox.ttf.PostScriptTable;
import org.apache.fontbox.ttf.TTFParser;
import org.apache.fontbox.ttf.TrueTypeFont;
@@ -81,6 +86,7 @@ public class PDTrueTypeFont extends PDSi
}
private final TrueTypeFont ttf;
+ private final OpenTypeFont otf;
private final boolean isEmbedded;
private final boolean isDamaged;
private CmapSubtable cmapWinUnicode = null;
@@ -112,9 +118,9 @@ public class PDTrueTypeFont extends PDSi
RandomAccessRead view = null;
try
{
- // embedded
- TTFParser ttfParser = new TTFParser(true);
view = ff2Stream.getCOSObject().createView();
+ // embedded
+ TTFParser ttfParser = getParser(view, true);
ttfFont = ttfParser.parse(view);
ttfFont.close();
}
@@ -142,6 +148,8 @@ public class PDTrueTypeFont extends PDSi
LOG.warn("Using fallback font " + ttfFont + " for " + getBaseFont());
}
}
+ otf = ttfFont instanceof OpenTypeFont && ((OpenTypeFont) ttfFont).isSupportedOTF()
+ ? (OpenTypeFont) ttfFont : null;
ttf = ttfFont;
readEncoding();
}
@@ -156,6 +164,8 @@ public class PDTrueTypeFont extends PDSi
encoding);
this.encoding = encoding;
this.ttf = ttf;
+ // OpenTypeFonts are not fully supported yet
+ otf = null;
setFontDescriptor(embedder.getFontDescriptor());
isEmbedded = true;
isDamaged = false;
@@ -470,6 +480,11 @@ public class PDTrueTypeFont extends PDSi
@Override
public GeneralPath getPath(int code) throws IOException
{
+ if (otf != null && otf.isPostScript())
+ {
+ GeneralPath path = getPathFromOutlines(code);
+ return path == null ? new GeneralPath() : path;
+ }
int gid = codeToGID(code);
GlyphTable glyphTable = ttf.getGlyph();
if (glyphTable == null)
@@ -532,22 +547,25 @@ public class PDTrueTypeFont extends PDSi
@Override
public GeneralPath getNormalizedPath(int code) throws IOException
{
- int gid = codeToGID(code);
-
- GeneralPath path = getPath(code);
-
- // Acrobat only draws GID 0 for embedded or "Standard 14" fonts, see PDFBOX-2372
- if (gid == 0 && !isEmbedded() && !isStandard14())
+ GeneralPath path = null;
+ if (otf != null && otf.isPostScript())
{
- path = null;
+ path = getPathFromOutlines(code);
+ }
+ else
+ {
+ int gid = codeToGID(code);
+ path = getPath(code);
+ // Acrobat only draws GID 0 for embedded or "Standard 14" fonts, see PDFBOX-2372
+ if (gid == 0 && !isEmbedded() && !isStandard14())
+ {
+ path = null;
+ }
}
-
if (path == null)
{
- // empty glyph (e.g. space, newline)
return new GeneralPath();
}
-
if (ttf.getUnitsPerEm() != 1000)
{
float scale = 1000f / ttf.getUnitsPerEm();
@@ -557,6 +575,16 @@ public class PDTrueTypeFont extends PDSi
return path;
}
+ private GeneralPath getPathFromOutlines(int code) throws IOException
+ {
+ CFFFont cffFont = otf.getCFF().getFont();
+ String name = getEncoding().getName(code);
+ int sid = cffFont.getCharset().getSID(name);
+ int gid = cffFont.getCharset().getGIDForSID(sid);
+ Type2CharString type2CharString = cffFont.getType2CharString(gid);
+ return type2CharString != null ? type2CharString.getPath() : null;
+ }
+
@Override
public boolean hasGlyph(String name) throws IOException
{
@@ -737,4 +765,28 @@ public class PDTrueTypeFont extends PDSi
}
cmapInitialized = true;
}
+
+ private TTFParser getParser(RandomAccessRead randomAccessRead, boolean isEmbedded)
+ throws IOException
+ {
+ long startPos = randomAccessRead.getPosition();
+ byte[] tagBytes = new byte[4];
+ int remainingBytes = tagBytes.length;
+ int amountRead;
+ while ((amountRead = randomAccessRead.read(tagBytes, tagBytes.length - remainingBytes,
+ remainingBytes)) > 0)
+ {
+ remainingBytes -= amountRead;
+ }
+ randomAccessRead.seek(startPos);
+ if ("OTTO".equals(new String(tagBytes, StandardCharsets.US_ASCII)))
+ {
+ return new OTFParser(isEmbedded);
+ }
+ else
+ {
+ return new TTFParser(isEmbedded);
+ }
+ }
+
}