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 2024/12/16 16:57:04 UTC

svn commit: r1922535 - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/text/PDFTextStripper.java test/java/org/apache/pdfbox/text/TestTextStripper.java

Author: tilman
Date: Mon Dec 16 16:57:04 2024
New Revision: 1922535

URL: http://svn.apache.org/viewvc?rev=1922535&view=rev
Log:
PDFBOX-3774: conditionally ignore spaces from the content stream; add setting + getter/setter + test + code simplification by Kevin Day

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java?rev=1922535&r1=1922534&r2=1922535&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java Mon Dec 16 16:57:04 2024
@@ -146,6 +146,7 @@ public class PDFTextStripper extends Leg
     private boolean shouldSeparateByBeads = true;
     private boolean sortByPosition = false;
     private boolean addMoreFormatting = false;
+    private boolean ignoreContentStreamSpaceGlyphs = false;
 
     private float indentThreshold = defaultIndentThreshold;
     private float dropThreshold = defaultDropThreshold;
@@ -523,11 +524,8 @@ public class PDFTextStripper extends Leg
                 {
                     IterativeMergeSort.sort(textList, comparator);
                 }
-                finally
-                {
-                    // PDFBOX-5487: Remove all space characters if contained within the adjacent letters
-                    removeContainedSpaces(textList);
-                }
+                // PDFBOX-5487: Remove all space characters if contained within the adjacent letters
+                removeContainedSpaces(textList);
             }
 
             startArticle();
@@ -555,6 +553,12 @@ public class PDFTextStripper extends Leg
                 PositionWrapper current = new PositionWrapper(position);
                 String characterValue = position.getUnicode();
 
+                // PDFBOX-3774: conditionally ignore spaces from the content stream
+                if (" ".equals(characterValue) && getIgnoreContentStreamSpaceGlyphs())
+                {
+                    continue;
+                }
+
                 // Resets the average character width when we see a change in font
                 // or a change in the font size
                 if (lastPosition != null &&
@@ -1277,6 +1281,32 @@ public class PDFTextStripper extends Leg
     }
 
     /**
+     * Determines whether spaces in the content stream text rendering instructions will be ignored
+     * during text extraction.
+     *
+     * @return true is space glyphs in the content stream text rendering instructions will be
+     * ignored - default is false
+     */
+    public boolean getIgnoreContentStreamSpaceGlyphs()
+    {
+        return ignoreContentStreamSpaceGlyphs;
+    }
+
+    /**
+     * Instruct the algorithm to ignore any spaces in the text rendering instructions in the content
+     * stream, and instead rely purely on the algorithm to determine where word breaks are.
+     *
+     * This can improve text extraction results where the content stream is sorted by position and
+     * has text overlapping spaces, but could cause some word breaks to not be added to the output
+     *
+     * @param newIgnoreContentStreamSpaceGlyphs whether PDF Box should ignore context stream spaces
+     */
+    public void setIgnoreContentStreamSpaceGlyphs(boolean newIgnoreContentStreamSpaceGlyphs)
+    {
+        ignoreContentStreamSpaceGlyphs = newIgnoreContentStreamSpaceGlyphs;
+    }
+
+    /**
      * Get the current space width-based tolerance value that is being used to estimate where spaces in text should be
      * added. Note that the default value for this has been determined from trial and error.
      * 

Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java?rev=1922535&r1=1922534&r2=1922535&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java Mon Dec 16 16:57:04 2024
@@ -54,9 +54,13 @@ import org.apache.logging.log4j.LogManag
 import org.apache.fontbox.util.BoundingBox;
 import org.apache.pdfbox.Loader;
 import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
 import org.apache.pdfbox.pdmodel.font.PDFont;
 import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
+import org.apache.pdfbox.pdmodel.font.PDType1Font;
 import org.apache.pdfbox.pdmodel.font.PDType3Font;
+import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
@@ -688,4 +692,51 @@ class TestTextStripper
             assertEquals(1378, text.replaceAll("\r", "").length());
         }
     }
+
+    /**
+     * PDFBOX-3774: test the IgnoreContentStreamSpaceGlyphs option.
+     *
+     * @throws Exception 
+     */
+    @Test
+    void testIgnoreContentStreamSpaceGlyphs() throws Exception
+    {
+        try (PDDocument doc = new PDDocument())
+        {
+            PDPage page = new PDPage();
+            try (PDPageContentStream cs = new PDPageContentStream(doc, page))
+            {
+                float fontHeight = 8;
+                float x = 50;
+                float y = page.getMediaBox().getHeight() - 50;
+                PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
+                cs.beginText();
+                cs.setFont(font, fontHeight);
+                cs.newLineAtOffset(x, y);
+                cs.showText("(                                      )");
+                cs.endText();
+
+                int indent = 6;
+                float overlapX = x + indent * font.getAverageFontWidth() / 1000f * fontHeight;
+                PDFont overlapFont = new PDType1Font(Standard14Fonts.FontName.TIMES_ROMAN);
+                cs.beginText();
+                cs.setFont(overlapFont, fontHeight * 2f);
+                cs.newLineAtOffset(overlapX, y);
+                cs.showText("overlap");
+                cs.endText();
+            }
+            doc.addPage(page);
+
+            PDFTextStripper localStripper = new PDFTextStripper();
+            localStripper.setLineSeparator("\n");
+            localStripper.setPageEnd("\n");
+            localStripper.setStartPage(1);
+            localStripper.setEndPage(1);
+            localStripper.setSortByPosition(true);
+
+            localStripper.setIgnoreContentStreamSpaceGlyphs(true);
+            String text = localStripper.getText(doc);
+            assertEquals("( overlap )\n", text);
+        }
+    }
 }