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 2016/03/17 18:25:39 UTC

svn commit: r1735463 - /pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/DrawPrintTextLocations.java

Author: tilman
Date: Thu Mar 17 17:25:39 2016
New Revision: 1735463

URL: http://svn.apache.org/viewvc?rev=1735463&view=rev
Log:
PDFBOX-3275: show glyph bounds; refactor existing code

Modified:
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/DrawPrintTextLocations.java

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/DrawPrintTextLocations.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/DrawPrintTextLocations.java?rev=1735463&r1=1735462&r2=1735463&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/DrawPrintTextLocations.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/DrawPrintTextLocations.java Thu Mar 17 17:25:39 2016
@@ -35,13 +35,20 @@ import org.apache.fontbox.util.BoundingB
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.font.PDCIDFontType2;
 import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDSimpleFont;
+import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.font.PDType3CharProc;
 import org.apache.pdfbox.pdmodel.font.PDType3Font;
+import org.apache.pdfbox.pdmodel.font.PDVectorFont;
 import org.apache.pdfbox.pdmodel.interactive.pagenavigation.PDThreadBead;
 import org.apache.pdfbox.rendering.PDFRenderer;
 import org.apache.pdfbox.text.PDFTextStripper;
 import org.apache.pdfbox.text.TextPosition;
 import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.Vector;
 
 /**
  * This is an example on how to get some x/y coordinates of text and to show them in a rendered
@@ -53,6 +60,8 @@ import org.apache.pdfbox.util.Matrix;
 public class DrawPrintTextLocations extends PDFTextStripper
 {
     private BufferedImage image;
+    private AffineTransform flipAT;
+    private AffineTransform rotateAT;
     private final String filename;
     static final int SCALE = 4;
     private Graphics2D g2d;
@@ -109,6 +118,88 @@ public class DrawPrintTextLocations exte
         }
     }
 
+    @Override
+    protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode, Vector displacement) throws IOException
+    {
+        super.showGlyph(textRenderingMatrix, font, code, unicode, displacement);
+
+        // in cyan:
+        // show actual glyph bounds. This must be done here and not in writeString(),
+        // because writeString processes only the glyphs with unicode, 
+        // see e.g. the file in PDFBOX-3274
+        Shape cyanShape = calculateGlyphBounds(textRenderingMatrix, font, code);
+
+        if (cyanShape != null)
+        {
+            cyanShape = flipAT.createTransformedShape(cyanShape);
+            cyanShape = rotateAT.createTransformedShape(cyanShape);
+
+            g2d.setColor(Color.CYAN);
+            g2d.draw(cyanShape);
+        }
+    }
+
+    // this calculates the real individual glyph bounds
+    private Shape calculateGlyphBounds(Matrix textRenderingMatrix, PDFont font, int code) throws IOException
+    {
+        GeneralPath path = null;
+        AffineTransform at = textRenderingMatrix.createAffineTransform();
+        at.concatenate(font.getFontMatrix().createAffineTransform());
+        if (font instanceof PDType3Font)
+        {
+            PDType3Font t3Font = (PDType3Font) font;
+            PDType3CharProc charProc = t3Font.getCharProc(code);
+            if (charProc != null)
+            {
+                PDRectangle glyphBBox = charProc.getGlyphBBox();
+                if (glyphBBox != null)
+                {
+                    path = glyphBBox.toGeneralPath();
+                }
+            }
+        }
+        else if (font instanceof PDVectorFont)
+        {
+            PDVectorFont vectorFont = (PDVectorFont) font;
+            path = vectorFont.getPath(code);
+
+            if (font instanceof PDTrueTypeFont)
+            {
+                PDTrueTypeFont ttFont = (PDTrueTypeFont) font;
+                int unitsPerEm = ttFont.getTrueTypeFont().getHeader().getUnitsPerEm();
+                at.scale(1000d / unitsPerEm, 1000d / unitsPerEm);
+            }
+            if (font instanceof PDType0Font)
+            {
+                PDType0Font t0font = (PDType0Font) font;
+                if (t0font.getDescendantFont() instanceof PDCIDFontType2)
+                {
+                    int unitsPerEm = ((PDCIDFontType2) t0font.getDescendantFont()).getTrueTypeFont().getHeader().getUnitsPerEm();
+                    at.scale(1000d / unitsPerEm, 1000d / unitsPerEm);
+                }
+            }
+        }
+        else if (font instanceof PDSimpleFont)
+        {
+            PDSimpleFont simpleFont = (PDSimpleFont) font;
+
+            // these two lines do not always work, e.g. for the TT fonts in file 032431.pdf
+            // which is why PDVectorFont is tried first.
+            String name = simpleFont.getEncoding().getName(code);
+            path = simpleFont.getPath(name);
+        }
+        else
+        {
+            // shouldn't happen, please open issue in JIRA
+            System.out.println("Unknown font class: " + font.getClass());
+        }
+        if (path == null)
+        {
+            return null;
+        }
+        return at.createTransformedShape(path.getBounds2D());
+    }
+
     private void stripPage(int page) throws IOException
     {
         PDFRenderer pdfRenderer = new PDFRenderer(document);
@@ -117,6 +208,34 @@ public class DrawPrintTextLocations exte
         PDPage pdPage = document.getPage(page);
         PDRectangle cropBox = pdPage.getCropBox();
 
+        // flip y-axis
+        flipAT = new AffineTransform();
+        flipAT.translate(0, pdPage.getBBox().getHeight());
+        flipAT.scale(1, -1);
+
+        // page may be rotated
+        rotateAT = new AffineTransform();
+        int rotation = pdPage.getRotation();
+        if (rotation != 0)
+        {
+            PDRectangle mediaBox = pdPage.getMediaBox();
+            switch (rotation)
+            {
+                case 90:
+                    rotateAT.translate(mediaBox.getHeight(), 0);
+                    break;
+                case 270:
+                    rotateAT.translate(0, mediaBox.getWidth());
+                    break;
+                case 180:
+                    rotateAT.translate(mediaBox.getWidth(), mediaBox.getHeight());
+                    break;
+                default:
+                    break;
+            }
+            rotateAT.rotate(Math.toRadians(rotation));
+        }
+
         g2d = image.createGraphics();
         g2d.setStroke(new BasicStroke(0.1f));
         g2d.scale(SCALE, SCALE);
@@ -134,10 +253,9 @@ public class DrawPrintTextLocations exte
         {
             PDRectangle r = bead.getRectangle();
             GeneralPath p = r.transform(Matrix.getTranslateInstance(-cropBox.getLowerLeftX(), cropBox.getLowerLeftY()));
-            AffineTransform flip = new AffineTransform();
-            flip.translate(0, pdPage.getBBox().getHeight());
-            flip.scale(1, -1);
-            Shape s = flip.createTransformedShape(p);
+
+            Shape s = flipAT.createTransformedShape(p);
+            s = rotateAT.createTransformedShape(s);
             g2d.setColor(Color.green);
             g2d.draw(s);
         }
@@ -200,39 +318,11 @@ public class DrawPrintTextLocations exte
             }
             Shape s = at.createTransformedShape(rect);
 
-            // flip y-axis
-            AffineTransform flip = new AffineTransform();
-            flip.translate(0, getCurrentPage().getBBox().getHeight());
-            flip.scale(1, -1);
-            s = flip.createTransformedShape(s);
-
-            AffineTransform transform = g2d.getTransform();
-            int rotation = getCurrentPage().getRotation();
-            if (rotation != 0)
-            {
-                PDRectangle mediaBox = getCurrentPage().getMediaBox();
-                switch (rotation)
-                {
-                    case 90:
-                        g2d.translate(mediaBox.getHeight(), 0);
-                        break;
-                    case 270:
-                        g2d.translate(0, mediaBox.getWidth());
-                        break;
-                    case 180:
-                        g2d.translate(mediaBox.getWidth(), mediaBox.getHeight());
-                        break;
-                    default:
-                        break;
-                }
-                g2d.rotate(Math.toRadians(rotation));
-            }
+            s = flipAT.createTransformedShape(s);
+            s = rotateAT.createTransformedShape(s);
+
             g2d.setColor(Color.blue);
             g2d.draw(s);
-            if (rotation != 0)
-            {
-                g2d.setTransform(transform);
-            }
         }
     }