You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2014/08/29 22:40:03 UTC
svn commit: r1621383 - in /pdfbox/branches/no-awt:
fontbox/src/main/java/org/apache/fontbox/cmap/
pdfbox/src/main/java/org/apache/pdfbox/cos/
pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/
pdfbox/src/main/java/org/apache/pdfbox/rendering/ pdfbox/...
Author: jahewson
Date: Fri Aug 29 20:40:02 2014
New Revision: 1621383
URL: http://svn.apache.org/r1621383
Log:
PDFBOX-2262/PDFBOX-2294: Implement vertical text rendering
Added:
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Vector.java
Modified:
pdfbox/branches/no-awt/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/font/CIDType0Glyph2D.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFTextStreamEngine.java
pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/operator/text/ShowTextGlyph.java
Modified: pdfbox/branches/no-awt/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java (original)
+++ pdfbox/branches/no-awt/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java Fri Aug 29 20:40:02 2014
@@ -286,6 +286,8 @@ public class CMap
{
this.codespaceRanges.addAll(cmap.codespaceRanges);
this.charToUnicode.putAll(cmap.charToUnicode);
+ this.codeToCid.putAll(cmap.codeToCid);
+ this.codeToCidRanges.addAll(cmap.codeToCidRanges);
}
/**
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Fri Aug 29 20:40:02 2014
@@ -179,6 +179,7 @@ public final class COSName extends COSBa
public static final COSName DUPLEX = new COSName("Duplex");
public static final COSName DV = new COSName("DV");
public static final COSName DW = new COSName("DW");
+ public static final COSName DW2 = new COSName("DW2");
// E
public static final COSName E = new COSName("E");
public static final COSName EARLY_CHANGE = new COSName("EarlyChange");
@@ -464,6 +465,7 @@ public final class COSName extends COSBa
public static final COSName VIEWER_PREFERENCES = new COSName("ViewerPreferences");
// W
public static final COSName W = new COSName("W");
+ public static final COSName W2 = new COSName("W2");
public static final COSName WHITE_POINT = new COSName("WhitePoint");
public static final COSName WIDTH = new COSName("Width");
public static final COSName WIDTHS = new COSName("Widths");
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java Fri Aug 29 20:40:02 2014
@@ -28,6 +28,7 @@ import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNumber;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.Vector;
/**
* A CIDFont. A CIDFont is a PDF object that contains information about a CIDFont program. Although
@@ -42,6 +43,10 @@ public abstract class PDCIDFont implemen
private Map<Integer, Float> widths;
private float defaultWidth;
+ private Map<Integer, Float> verticalDisplacementY = new HashMap<Integer, Float>(); // w1y
+ private Map<Integer, Vector> positionVectors = new HashMap<Integer, Vector>(); // v
+ private float[] dw2;
+
protected final COSDictionary dict;
private PDFontDescriptor fontDescriptor;
@@ -55,44 +60,96 @@ public abstract class PDCIDFont implemen
this.dict = fontDictionary;
this.parent = parent;
readWidths();
+ readVerticalDisplacements();
}
private void readWidths()
{
- if (widths == null)
+ widths = new HashMap<Integer, Float>();
+ COSArray widths = (COSArray) dict.getDictionaryObject(COSName.W);
+ if (widths != null)
{
- widths = new HashMap<Integer, Float>();
- COSArray widths = (COSArray) dict.getDictionaryObject(COSName.W);
- if (widths != null)
+ int size = widths.size();
+ int counter = 0;
+ while (counter < size)
{
- int size = widths.size();
- int counter = 0;
- while (counter < size)
+ COSNumber firstCode = (COSNumber) widths.getObject(counter++);
+ COSBase next = widths.getObject(counter++);
+ if (next instanceof COSArray)
{
- COSNumber firstCode = (COSNumber) widths.getObject(counter++);
- COSBase next = widths.getObject(counter++);
- if (next instanceof COSArray)
+ COSArray array = (COSArray) next;
+ int startRange = firstCode.intValue();
+ int arraySize = array.size();
+ for (int i = 0; i < arraySize; i++)
{
- COSArray array = (COSArray) next;
- int startRange = firstCode.intValue();
- int arraySize = array.size();
- for (int i = 0; i < arraySize; i++)
- {
- COSNumber width = (COSNumber) array.get(i);
- this.widths.put(startRange + i, width.floatValue());
- }
+ COSNumber width = (COSNumber) array.get(i);
+ this.widths.put(startRange + i, width.floatValue());
}
- else
+ }
+ else
+ {
+ COSNumber secondCode = (COSNumber) next;
+ COSNumber rangeWidth = (COSNumber) widths.getObject(counter++);
+ int startRange = firstCode.intValue();
+ int endRange = secondCode.intValue();
+ float width = rangeWidth.floatValue();
+ for (int i = startRange; i <= endRange; i++)
{
- COSNumber secondCode = (COSNumber) next;
- COSNumber rangeWidth = (COSNumber) widths.getObject(counter++);
- int startRange = firstCode.intValue();
- int endRange = secondCode.intValue();
- float width = rangeWidth.floatValue();
- for (int i = startRange; i <= endRange; i++)
- {
- this.widths.put(i, width);
- }
+ this.widths.put(i, width);
+ }
+ }
+ }
+ }
+
+ }
+
+ private void readVerticalDisplacements()
+ {
+ // default position vector and vertical displacement vector
+ COSArray cosDW2 = (COSArray) dict.getDictionaryObject(COSName.DW2);
+ if (cosDW2 != null)
+ {
+ dw2 = new float[2];
+ dw2[0] = ((COSNumber)cosDW2.get(0)).floatValue();
+ dw2[1] = ((COSNumber)cosDW2.get(1)).floatValue();
+ }
+ else
+ {
+ dw2 = new float[] { 880, -1000 };
+ }
+
+ // vertical metrics for individual CIDs.
+ COSArray w2 = (COSArray) dict.getDictionaryObject(COSName.W2);
+ if (w2 != null)
+ {
+ for (int i = 0; i < w2.size(); i++)
+ {
+ COSNumber c = (COSNumber)w2.get(i);
+ COSBase next = w2.get(++i);
+ if (next instanceof COSArray)
+ {
+ COSArray array = (COSArray)next;
+ for (int j = 0; j < array.size(); j++)
+ {
+ int cid = c.intValue() + j;
+ COSNumber w1y = (COSNumber) array.get(j);
+ COSNumber v1x = (COSNumber) array.get(++j);
+ COSNumber v1y = (COSNumber) array.get(++j);
+ verticalDisplacementY.put(cid, w1y.floatValue());
+ positionVectors.put(cid, new Vector(v1x.floatValue(), v1y.floatValue()));
+ }
+ }
+ else
+ {
+ int first = c.intValue();
+ int last = ((COSNumber) next).intValue();
+ COSNumber w1y = (COSNumber) w2.get(++i);
+ COSNumber v1x = (COSNumber) w2.get(++i);
+ COSNumber v1y = (COSNumber) w2.get(++i);
+ for (int cid = first; cid <= last; cid++)
+ {
+ verticalDisplacementY.put(cid, w1y.floatValue());
+ positionVectors.put(cid, new Vector(v1x.floatValue(), v1y.floatValue()));
}
}
}
@@ -176,6 +233,74 @@ public abstract class PDCIDFont implemen
}
/**
+ * Returns the default position vector (v).
+ *
+ * @param cid CID
+ */
+ private Vector getDefaultPositionVector(int cid)
+ {
+ float w0;
+ if (widths.containsKey(cid))
+ {
+ Float w = widths.get(cid);
+ if (w != null)
+ {
+ w0 = w;
+ }
+ else
+ {
+ w0 = getDefaultWidth();
+ }
+ }
+ else
+ {
+ w0 = getDefaultWidth();
+ }
+
+ return new Vector(w0 / 2, dw2[0]);
+ }
+
+ /**
+ * Returns the position vector (v) for the given character code.
+ *
+ * @param code character code
+ * @return position vector (v)
+ */
+ public Vector getPositionVector(int code)
+ {
+ int cid = codeToCID(code);
+ Vector v = positionVectors.get(cid);
+ if (v != null)
+ {
+ return v;
+ }
+ else
+ {
+ return getDefaultPositionVector(cid);
+ }
+ }
+
+ /**
+ * Returns the y-component of the vertical displacement vector (w1).
+ *
+ * @param code character code
+ * @return w1y
+ */
+ public float getVerticalDisplacementVectorY(int code)
+ {
+ int cid = codeToCID(code);
+ Float w1y = verticalDisplacementY.get(cid);
+ if (w1y != null)
+ {
+ return w1y;
+ }
+ else
+ {
+ return dw2[1];
+ }
+ }
+
+ /**
* This will get the font height for a character.
*
* @param code character code
@@ -195,7 +320,7 @@ public abstract class PDCIDFont implemen
// font widths with the widths given in the font dictionary
int cid = codeToCID(code);
- if (cid < widths.size())
+ if (widths.containsKey(cid))
{
Float w = widths.get(cid);
if (w != null)
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java Fri Aug 29 20:40:02 2014
@@ -169,8 +169,7 @@ public class PDCIDFontType2 extends PDCI
return cMap.toUnicode(code).codePointAt(0); // actually: code -> CID
}
- // CID CMap is not used for TTF, even if present, see see PDFBOX-1422
- return code;
+ return cMap.toCID(code);
}
/**
@@ -181,18 +180,6 @@ public class PDCIDFontType2 extends PDCI
*/
public int codeToGID(int code) throws IOException
{
- int cid = codeToCID(code);
- return cidToGID(cid);
- }
-
- /**
- * Returns the GID for the given CID.
- *
- * @param cid the given CID (for TTF this is the same as the character code)
- * @return the mapped GID
- */
- public int cidToGID(int cid) throws IOException
- {
if (!isEmbedded)
{
// The conforming reader shall select glyphs by translating characters from the
@@ -205,6 +192,7 @@ public class PDCIDFontType2 extends PDCI
if (cid2gid != null || hasIdentityCid2Gid)
{
+ int cid = codeToCID(code);
// strange but true, Acrobat allows non-embedded GIDs, test with PDFBOX-2060
if (hasIdentityCid2Gid)
{
@@ -215,7 +203,7 @@ public class PDCIDFontType2 extends PDCI
return cid2gid[cid];
}
}
- if (!parent.isSymbolic())
+ else if (!parent.isSymbolic())
{
// this nonsymbolic behaviour isn't well documented, test with PDFBOX-1422
@@ -234,7 +222,7 @@ public class PDCIDFontType2 extends PDCI
// Any undefined entries in the table shall be filled using StandardEncoding
if (name == null)
{
- name = StandardEncoding.INSTANCE.getName(cid); // code = CID for TTF
+ name = StandardEncoding.INSTANCE.getName(code);
}
// map to a Unicode value using the Adobe Glyph List
@@ -242,6 +230,7 @@ public class PDCIDFontType2 extends PDCI
}
else
{
+ int cid = codeToCID(code);
unicode = parent.toUnicode(cid); // code = CID for TTF
}
@@ -261,6 +250,7 @@ public class PDCIDFontType2 extends PDCI
// a CIDToGIDMap entry that maps CIDs to the glyph indices for the appropriate glyph
// descriptions in that font program.
+ int cid = codeToCID(code);
if (cid2gid != null)
{
// use CIDToGIDMap
@@ -326,8 +316,7 @@ public class PDCIDFontType2 extends PDCI
@Override
protected float getWidthFromFont(int code) throws IOException
{
- int cid = codeToCID(code);
- int gid = cidToGID(cid);
+ int gid = codeToGID(code);
int width = ttf.getAdvanceWidth(gid);
int unitsPerEM = ttf.getUnitsPerEm();
if (unitsPerEM != 1000)
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java Fri Aug 29 20:40:02 2014
@@ -157,7 +157,7 @@ public abstract class PDFont implements
}
/**
- * Returns the width of the given character, in glyph space.
+ * Returns the advance width of the given character, in glyph space.
*
* @param code character code
*/
@@ -469,6 +469,11 @@ public abstract class PDFont implements
}
/**
+ * Returns true if the font uses vertical writing mode.
+ */
+ public abstract boolean isVertical();
+
+ /**
* Calling this will release all cached information.
*/
public void clear()
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java Fri Aug 29 20:40:02 2014
@@ -236,6 +236,12 @@ public abstract class PDSimpleFont exten
return null;
}
+ @Override
+ public boolean isVertical()
+ {
+ return false;
+ }
+
/**
* Returns true if this font is one of the "standard 14" fonts.
*/
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java Fri Aug 29 20:40:02 2014
@@ -27,6 +27,8 @@ import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.encoding.GlyphList;
+import org.apache.pdfbox.encoding.StandardEncoding;
import org.apache.pdfbox.util.Matrix;
/**
@@ -62,6 +64,12 @@ public class PDType0Font extends PDFont
readEncoding();
fetchCMapUCS2();
descendantFont = PDFontFactory.createDescendantFont(descendantFontDictionary, this);
+
+ // warn if there may be text extraction issues
+ if (!isSymbolic())
+ {
+ LOG.warn("Nonsymbolic Type 0 font: " + getName());
+ }
}
/**
@@ -173,6 +181,12 @@ public class PDType0Font extends PDFont
}
@Override
+ public boolean isVertical()
+ {
+ return cMap.getWMode() == 1;
+ }
+
+ @Override
public float getHeight(int code) throws IOException
{
return descendantFont.getHeight(code);
@@ -212,10 +226,18 @@ public class PDType0Font extends PDFont
return unicode;
}
- // if the font is composite and uses a predefined cmap (excluding Identity-H/V) then
- // or if its decendant font uses Adobe-GB1/CNS1/Japan1/Korea1
- if (isCMapPredefined && cMapUCS2 != null)
+ if (!isSymbolic())
{
+ // this nonsymbolic behaviour isn't well documented, test with PDFBOX-1422,
+ // also see PDCIDFontType2#cidToGID()
+ String name = StandardEncoding.INSTANCE.getName(code);
+ return GlyphList.toUnicode(name);
+ }
+ else if (isCMapPredefined && cMapUCS2 != null)
+ {
+ // if the font is composite and uses a predefined cmap (excluding Identity-H/V) then
+ // or if its decendant font uses Adobe-GB1/CNS1/Japan1/Korea1
+
// e) Map the CID according to the CMap from step d), producing a Unicode value
return cMapUCS2.toUnicode(code);
}
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Fri Aug 29 20:40:02 2014
@@ -249,7 +249,7 @@ public class PageDrawer extends PDFGraph
}
@Override
- protected void processText(byte[] string) throws IOException
+ protected void showText(byte[] string, float adjustment) throws IOException
{
PDGraphicsState state = getGraphicsState();
RenderingMode renderingMode = state.getTextState().getRenderingMode();
@@ -260,7 +260,7 @@ public class PageDrawer extends PDFGraph
textClippingArea = new Area();
}
- super.processText(string);
+ super.showText(string, adjustment);
// apply the buffered clip as one area
if (renderingMode.isClip())
@@ -271,8 +271,8 @@ public class PageDrawer extends PDFGraph
}
@Override
- protected void processGlyph(Matrix textRenderingMatrix, float dx, float dy, int code,
- String unicode, PDFont font) throws IOException
+ protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode,
+ float dx, float dy) throws IOException
{
try
{
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/font/CIDType0Glyph2D.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/font/CIDType0Glyph2D.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/font/CIDType0Glyph2D.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/rendering/font/CIDType0Glyph2D.java Fri Aug 29 20:40:02 2014
@@ -53,9 +53,9 @@ public class CIDType0Glyph2D implements
public GeneralPath getPathForCharacterCode(int code)
{
int cid = font.getParent().codeToCID(code);
- if (cache.containsKey(cid))
+ if (cache.containsKey(code))
{
- return cache.get(cid);
+ return cache.get(code);
}
// don't draw CID 0
@@ -63,7 +63,7 @@ public class CIDType0Glyph2D implements
{
LOG.warn("No glyph for " + code + " (CID 0000) in font " + fontName);
GeneralPath path = new GeneralPath();
- cache.put(cid, path);
+ cache.put(code, path);
return path;
}
@@ -78,7 +78,7 @@ public class CIDType0Glyph2D implements
}
GeneralPath path = charString.getPath();
- cache.put(cid, path);
+ cache.put(code, path);
return path;
}
catch (IOException e)
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java Fri Aug 29 20:40:02 2014
@@ -192,6 +192,17 @@ public class Matrix implements Cloneable
}
/**
+ * Translates this matrix by the given vector.
+ *
+ * @param vector 2D vector
+ */
+ public void translate(Vector vector)
+ {
+ Matrix m = Matrix.getTranslatingInstance(vector.getX(), vector.getY());
+ concatenate(m);
+ }
+
+ /**
* This will take the current matrix and multipy it with a matrix that is passed in.
*
* @param b The matrix to multiply by.
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java Fri Aug 29 20:40:02 2014
@@ -16,7 +16,6 @@
*/
package org.apache.pdfbox.util;
-import java.awt.Point;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.io.ByteArrayInputStream;
@@ -44,6 +43,7 @@ import org.apache.pdfbox.pdmodel.PDResou
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDFontFactory;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType3Font;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
@@ -313,7 +313,7 @@ public class PDFStreamEngine
*/
public void showText(byte[] string) throws IOException
{
- processText(string);
+ showText(string, 0);
}
/**
@@ -325,40 +325,21 @@ public class PDFStreamEngine
*/
public void showAdjustedText(List<byte[]> strings, List<Float> adjustments) throws IOException
{
- float fontsize = getGraphicsState().getTextState().getFontSize();
- float horizontalScaling = getGraphicsState().getTextState().getHorizontalScaling() / 100;
for (int i = 0, len = strings.size(); i < len; i++)
{
- float adjustment = adjustments.get(i);
- Matrix adjMatrix = new Matrix();
- adjustment =- (adjustment / 1000) * horizontalScaling * fontsize;
- // TODO vertical writing mode
- adjMatrix.setValue( 2, 0, adjustment );
- showAdjustedTextRun(strings.get(i), adjMatrix);
+ showText(strings.get(i), adjustments.get(i));
}
}
/**
- * Called when a single run of text with a spacing adjustment is to be shown.
- *
- * @param string the encoded text
- * @param adjustment spacing adjustment to apply before showing the string
- * @throws IOException if there was an error showing the text
- */
- protected void showAdjustedTextRun(byte[] string, Matrix adjustment) throws IOException
- {
- setTextMatrix(adjustment.multiply(getTextMatrix(), adjustment));
- processText(string);
- }
-
- /**
* Process text from the PDF Stream. You should override this method if you want to
* perform an action when encoded text is being processed.
- *
+ *
* @param string the encoded text
+ * @param adjustment a position adjustment from a TJ array to be applied after the glyph
* @throws IOException if there is an error processing the string
*/
- protected void processText(byte[] string) throws IOException
+ protected void showText(byte[] string, float adjustment) throws IOException
{
PDGraphicsState state = getGraphicsState();
PDTextState textState = state.getTextState();
@@ -373,7 +354,7 @@ public class PDFStreamEngine
float fontSize = textState.getFontSize();
float horizontalScaling = textState.getHorizontalScaling() / 100f;
- float characterSpacing = textState.getCharacterSpacing();
+ float charSpacing = textState.getCharacterSpacing();
// put the text state parameters into matrix form
Matrix parameters = new Matrix(
@@ -403,32 +384,66 @@ public class PDFStreamEngine
}
}
+ // text rendering matrix (text space -> device space)
+ Matrix ctm = state.getCurrentTransformationMatrix();
+ Matrix textRenderingMatrix = parameters.multiply(textMatrix).multiply(ctm);
+
// get glyph's horizontal and vertical displacements (glyph space -> text space)
+ // todo: it would be nice to encapsulate the code below
float w0, w1;
if (font instanceof PDType3Font)
{
// Type 3 fonts specify a custom matrix
- Point2D adv = font.getFontMatrix().transform(font.getWidth(code), font.getHeight(code));
+ Matrix fontMatrix = font.getFontMatrix();
+ Point2D adv = fontMatrix.transform(font.getWidth(code), font.getHeight(code));
w0 = (float)adv.getX();
w1 = (float)adv.getY();
}
else
{
// all other fonts use 1:1000 for widths, even those with a FontMatrix, see FOP-2252
- w0 = font.getWidth(code) / 1000f;
- w1 = 0; // todo: support vertical writing mode
- }
+ if (font.isVertical())
+ {
+ PDType0Font type0 = (PDType0Font)font;
- // text rendering matrix (text space -> device space)
- Matrix ctm = state.getCurrentTransformationMatrix();
- Matrix textRenderingMatrix = parameters.multiply(textMatrix).multiply(ctm);
+ // position vector (position of vertical origin relative to horizontal origin)
+ Vector v = type0.getDescendantFont().getPositionVector(code);
+ textRenderingMatrix.translate(v.scale(-1 / 1000f));
+
+ // displacement vector
+ w0 = 0;
+ w1 = type0.getDescendantFont().getVerticalDisplacementVectorY(code) / 1000;
+ }
+ else
+ {
+ // displacement vector
+ w0 = font.getWidth(code) / 1000f;
+ w1 = 0;
+ }
+ }
// process the decoded glyph
- processGlyph(textRenderingMatrix, w0, w1, code, unicode, font);
+ showGlyph(textRenderingMatrix, font, code, unicode, w0, w1);
+
+ // TJ adjustment after final glyph
+ float tj = 0;
+ if (in.available() == 0)
+ {
+ tj = adjustment;
+ }
// calculate the combined displacements
- float tx = (w0 * fontSize + characterSpacing + wordSpacing) * horizontalScaling;
- float ty = 0; // todo: support vertical writing mode
+ float tx, ty;
+ if (font.isVertical())
+ {
+ tx = 0;
+ ty = (w1 - tj / 1000) * fontSize + charSpacing + wordSpacing;
+ }
+ else
+ {
+ tx = ((w0 - tj / 1000) * fontSize + charSpacing + wordSpacing) * horizontalScaling;
+ ty = 0;
+ }
// update the text matrix
textMatrix.concatenate(Matrix.getTranslatingInstance(tx, ty));
@@ -440,15 +455,15 @@ public class PDFStreamEngine
* the default implementation does nothing.
*
* @param textRenderingMatrix the current text rendering matrix, T<sub>rm</sub>
- * @param dx the x-advance of the glyph in text space
- * @param dy the y-advance of the glyph in text space
+ * @param font the current font
* @param code internal PDF character code for the glyph
* @param unicode the Unicode text for this glyph, or null if the PDF does provide it
- * @param font the current font
+ * @param dx the x-advance of the glyph in text space
+ * @param dy the y-advance of the glyph in text space
* @throws IOException if the glyph cannot be processed
*/
- protected void processGlyph(Matrix textRenderingMatrix, float dx, float dy, int code,
- String unicode, PDFont font) throws IOException
+ protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode,
+ float dx, float dy) throws IOException
{
// overridden in subclasses
}
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFTextStreamEngine.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFTextStreamEngine.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFTextStreamEngine.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/PDFTextStreamEngine.java Fri Aug 29 20:40:02 2014
@@ -27,7 +27,6 @@ import org.apache.pdfbox.pdmodel.font.PD
import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
import org.apache.pdfbox.text.TextPosition;
-import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.Properties;
@@ -82,8 +81,8 @@ public class PDFTextStreamEngine extends
* This method was originally written by Ben Litchfield for PDFStreamEngine.
*/
@Override
- protected void processGlyph(Matrix textRenderingMatrix, float dx, float dy, int code,
- String unicode, PDFont font) throws IOException
+ protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode,
+ float dx, float dy) throws IOException
{
//
// legacy calculations which were previously in PDFStreamEngine
Added: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Vector.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Vector.java?rev=1621383&view=auto
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Vector.java (added)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/Vector.java Fri Aug 29 20:40:02 2014
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+package org.apache.pdfbox.util;
+
+/**
+ * A 2D vector.
+ *
+ * @author John Hewson
+ */
+public final class Vector
+{
+ private final float x, y;
+
+ public Vector(float x, float y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Returns the x magnitude.
+ */
+ public float getX()
+ {
+ return x;
+ }
+
+ /**
+ * Returns the y magnitude.
+ */
+ public float getY()
+ {
+ return y;
+ }
+
+ /**
+ * Returns a new vector scaled by both x and y.
+ *
+ * @param sxy x and y scale
+ */
+ public Vector scale(float sxy)
+ {
+ return new Vector(x * sxy, y * sxy);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "(" + x + ", " + y + ")";
+ }
+}
Modified: pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/operator/text/ShowTextGlyph.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/operator/text/ShowTextGlyph.java?rev=1621383&r1=1621382&r2=1621383&view=diff
==============================================================================
--- pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/operator/text/ShowTextGlyph.java (original)
+++ pdfbox/branches/no-awt/pdfbox/src/main/java/org/apache/pdfbox/util/operator/text/ShowTextGlyph.java Fri Aug 29 20:40:02 2014
@@ -41,24 +41,24 @@ public class ShowTextGlyph extends Opera
List<Float> adjustments = new ArrayList<Float>();
List<byte[]> strings = new ArrayList<byte[]>();
- boolean lastWasAdjustment = false;
+ boolean lastWasString = false;
for(int i = 0, len = array.size(); i < len; i++)
{
COSBase next = array.get(i);
- if(next instanceof COSNumber)
+ if (next instanceof COSNumber)
{
adjustments.add(((COSNumber)next).floatValue());
- lastWasAdjustment = true;
+ lastWasString = false;
}
else if(next instanceof COSString)
{
- if (!lastWasAdjustment)
+ if (lastWasString)
{
- adjustments.add(0f);
+ adjustments.add(0f); // adjustment for previous string
}
strings.add(((COSString)next).getBytes());
- lastWasAdjustment = false;
+ lastWasString = true;
}
else
{
@@ -66,6 +66,12 @@ public class ShowTextGlyph extends Opera
}
}
+ // adjustment for final string
+ if (lastWasString)
+ {
+ adjustments.add(0f);
+ }
+
context.showAdjustedText(strings, adjustments);
}
}