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:09 UTC

svn commit: r1922536 - in /pdfbox/branches/2.0/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:08 2024
New Revision: 1922536

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

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

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java?rev=1922536&r1=1922535&r2=1922536&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java Mon Dec 16 16:57:08 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;
@@ -526,11 +527,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();
@@ -558,6 +556,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 && (position.getFont() != lastPosition.getTextPosition()
@@ -1286,6 +1290,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/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java?rev=1922536&r1=1922535&r2=1922536&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/text/TestTextStripper.java Mon Dec 16 16:57:08 2024
@@ -48,9 +48,12 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fontbox.util.BoundingBox;
 import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
 import org.apache.pdfbox.pdmodel.TestPDPageTree;
 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.interactive.documentnavigation.destination.PDPageDestination;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
@@ -743,4 +746,49 @@ public class TestTextStripper extends Te
         assertEquals(1378, text.replaceAll("\r", "").length());
         doc.close();
     }
+
+    /**
+     * PDFBOX-3774: test the IgnoreContentStreamSpaceGlyphs option.
+     *
+     * @throws Exception 
+     */
+    public void testIgnoreContentStreamSpaceGlyphs() throws Exception
+    {
+        PDDocument doc = new PDDocument();
+        PDPage page = new PDPage();
+        PDPageContentStream cs = new PDPageContentStream(doc, page);
+
+        float fontHeight = 8;
+        float x = 50;
+        float y = page.getMediaBox().getHeight() - 50;
+        PDFont font = PDType1Font.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 = PDType1Font.TIMES_ROMAN;
+        cs.beginText();
+        cs.setFont(overlapFont, fontHeight * 2f);
+        cs.newLineAtOffset(overlapX, y);
+        cs.showText("overlap");
+        cs.endText();
+        cs.close();
+        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);
+        doc.close();
+    }
 }