You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2018/02/15 20:43:42 UTC
svn commit: r1824363 - in
/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font:
PDCIDFont.java PDCIDFontType2.java
Author: tilman
Date: Thu Feb 15 20:43:42 2018
New Revision: 1824363
URL: http://svn.apache.org/viewvc?rev=1824363&view=rev
Log:
PDFBOX-4106: Use 'vhea' and 'vmtx' tables to fix vertical displacements, by Aaron Madlon-Kay
PDFBOX-4093: make method that is called from constructor final
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java?rev=1824363&r1=1824362&r2=1824363&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java Thu Feb 15 20:43:42 2018
@@ -49,9 +49,9 @@ public abstract class PDCIDFont implemen
private float defaultWidth;
private float averageWidth;
- private final Map<Integer, Float> verticalDisplacementY = new HashMap<>(); // w1y
- private final Map<Integer, Vector> positionVectors = new HashMap<>(); // v
- private float[] dw2 = new float[] { 880, -1000 };
+ final Map<Integer, Float> verticalDisplacementY = new HashMap<>(); // w1y
+ final Map<Integer, Vector> positionVectors = new HashMap<>(); // v
+ float[] dw2 = new float[] { 880, -1000 };
protected final COSDictionary dict;
private PDFontDescriptor fontDescriptor;
@@ -359,6 +359,7 @@ public abstract class PDCIDFont implemen
*
* @param code character code
* @return GID
+ * @throws java.io.IOException
*/
public abstract int codeToGID(int code) throws IOException;
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=1824363&r1=1824362&r2=1824363&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 Feb 15 20:43:42 2018
@@ -19,20 +19,32 @@ package org.apache.pdfbox.pdmodel.font;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.HorizontalMetricsTable;
import org.apache.fontbox.ttf.OTFParser;
import org.apache.fontbox.ttf.OpenTypeFont;
import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.fontbox.ttf.VerticalHeaderTable;
+import org.apache.fontbox.ttf.VerticalMetricsTable;
import org.apache.fontbox.util.BoundingBox;
+import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.Vector;
/**
* Type 2 CIDFont (TrueType).
@@ -141,6 +153,85 @@ public class PDCIDFontType2 extends PDCI
}
cmap = ttf.getUnicodeCmapLookup(false);
cid2gid = readCIDToGIDMap();
+ fixVerticalDisplacements();
+ }
+
+ private void fixVerticalDisplacements() throws IOException
+ {
+ if (!parent.dict.getCOSName(COSName.ENCODING).equals(COSName.IDENTITY_V))
+ {
+ return;
+ }
+ // The "vhea" and "vmtx" tables that specify vertical metrics shall never be used by a conforming
+ // reader. The only way to specify vertical metrics in PDF shall be by means of the DW2 and W2
+ // entries in a CIDFont dictionary.
+ VerticalHeaderTable vhea = ttf.getVerticalHeader();
+ if (vhea == null)
+ {
+ if (dict.getItem(COSName.DW2) == null)
+ {
+ LOG.warn("Identity-V font seems to be missing vertical metrics: it has no 'vhea' table and no DW2 entry");
+ }
+ return;
+ }
+ // Clear any data previously set from DW2 / W2
+ verticalDisplacementY.clear();
+ positionVectors.clear();
+
+ float scaling = 1000f / ttf.getHeader().getUnitsPerEm();
+
+ dw2[0] = vhea.getAscender() * scaling;
+ dw2[1] = -vhea.getAdvanceHeightMax() * scaling;
+ Map<Integer, Integer> gid2cid = invert(cid2gid);
+ HorizontalMetricsTable hmtx = ttf.getHorizontalMetrics();
+ VerticalMetricsTable vmtx = ttf.getVerticalMetrics();
+ for (int gid = 0; gid < ttf.getNumberOfGlyphs(); gid++)
+ {
+ float advance = -vmtx.getAdvanceHeight(gid) * scaling;
+ if (advance != dw2[1])
+ {
+ int cid = gid2cid == null ? gid : gid2cid.get(gid);
+ verticalDisplacementY.put(cid, advance);
+ positionVectors.put(cid, new Vector(hmtx.getAdvanceWidth(gid) / 2f, dw2[0]));
+ }
+ }
+ freezeVerticalPositions();
+ }
+
+ private void freezeVerticalPositions() throws IOException
+ {
+ COSArray cosDw2 = new COSArray();
+ cosDw2.add(COSInteger.get(Math.round(dw2[0])));
+ cosDw2.add(COSInteger.get(Math.round(dw2[1])));
+ dict.setItem(COSName.DW2, cosDw2);
+
+ COSArray cosW2 = new COSArray();
+ COSArray values = new COSArray();
+ int prev = Integer.MIN_VALUE;
+ Set<Integer> keys = new TreeSet<>(verticalDisplacementY.keySet());
+ for (int cid : keys)
+ {
+ long w1 = Math.round(verticalDisplacementY.get(cid));
+ if (w1 == dw2[1])
+ {
+ continue;
+ }
+ Vector pos = positionVectors.get(cid);
+ long v_x = Math.round(pos.getX());
+ long v_y = Math.round(pos.getY());
+ // c [w1_1y v_1x v_1y w1_2y v_2x v_2y ... w1_ny v_nx v_ny]
+ if (prev != cid - 1)
+ {
+ values = new COSArray();
+ cosW2.add(COSInteger.get(cid)); // c
+ cosW2.add(values);
+ }
+ values.add(COSInteger.get(w1)); // w1_iy
+ values.add(COSInteger.get(v_x)); // v_ix
+ values.add(COSInteger.get(v_y)); // v_iy
+ prev = cid;
+ }
+ dict.setItem(COSName.W2, cosW2);
}
private TrueTypeFont findFontOrSubstitute() throws IOException
@@ -188,7 +279,8 @@ public class PDCIDFontType2 extends PDCI
private BoundingBox generateBoundingBox() throws IOException
{
- if (getFontDescriptor() != null) {
+ if (getFontDescriptor() != null)
+ {
PDRectangle bbox = getFontDescriptor().getFontBoundingBox();
if (bbox != null &&
(bbox.getLowerLeftX() != 0 || bbox.getLowerLeftY() != 0
@@ -215,6 +307,20 @@ public class PDCIDFontType2 extends PDCI
return cMap.toCID(code);
}
+ private Map<Integer, Integer> invert(int[] cid2gid)
+ {
+ if (cid2gid == null)
+ {
+ return null;
+ }
+ Map<Integer, Integer> inverse = new HashMap<>(cid2gid.length);
+ for (int i = 0; i < cid2gid.length; i++)
+ {
+ inverse.put(cid2gid[i], i);
+ }
+ return inverse;
+ }
+
/**
* Returns the GID for the given character code.
*