diff --git a/src/Document/Object/Decorator/Page.php b/src/Document/Object/Decorator/Page.php index b665daf3..89efba17 100644 --- a/src/Document/Object/Decorator/Page.php +++ b/src/Document/Object/Decorator/Page.php @@ -3,7 +3,6 @@ namespace PrinsFrank\PdfParser\Document\Object\Decorator; use PrinsFrank\MarkDownDom\Renderer\MarkdownRenderer; -use PrinsFrank\MarkDownDom\Renderer\TextRenderer; use PrinsFrank\PdfParser\Document\ContentStream\ContentStream; use PrinsFrank\PdfParser\Document\ContentStream\ContentStreamParser; use PrinsFrank\PdfParser\Document\ContentStream\PositionedText\PositionedTextElement; @@ -16,7 +15,8 @@ use PrinsFrank\PdfParser\Exception\InvalidArgumentException; use PrinsFrank\PdfParser\Exception\ParseFailureException; use PrinsFrank\PdfParser\Exception\PdfParserException; -use PrinsFrank\PdfParser\Extraction\Markdown\MarkdownExtractor; +use PrinsFrank\PdfParser\Extraction\MarkdownExtractor; +use PrinsFrank\PdfParser\Extraction\TextExtractor; class Page extends DecoratedObject { /** @@ -30,8 +30,7 @@ public function getPositionedTextElements(): array { /** @throws PdfParserException */ public function getText(): string { - return (new TextRenderer()) - ->render(MarkdownExtractor::extractContent($this->getPositionedTextElements(), $this)); + return TextExtractor::extractContent($this->getPositionedTextElements(), $this); } public function getMarkdown(): string { diff --git a/src/Extraction/Markdown/MarkdownExtractor.php b/src/Extraction/MarkdownExtractor.php similarity index 83% rename from src/Extraction/Markdown/MarkdownExtractor.php rename to src/Extraction/MarkdownExtractor.php index 98681808..69d271ef 100644 --- a/src/Extraction/Markdown/MarkdownExtractor.php +++ b/src/Extraction/MarkdownExtractor.php @@ -1,6 +1,6 @@ absoluteMatrix->offsetX - - $previousTextElementOnLine->absoluteMatrix->offsetX - - $previousTextElementOnLine->getAdvanceWidth($previousFontOnLine); - - $wordBreakThreshold = $previousTextElementOnLine->textState->getFontSize() - * $previousTextElementOnLine->absoluteMatrix->scaleX - * ($previousTextElementOnLine->textState->scale / 100) - * PositionedTextElement::WORD_BREAK_THRESHOLD_EM; - - if ( - $gap >= $wordBreakThreshold - && $previousTextElementEndsWithSpace === false - && str_starts_with($elementText, ' ') === false - ) { - $textBuffer .= ' '; - } + if ($previousTextElementEndsWithSpace === false + && str_starts_with($elementText, ' ') === false + && $previousTextElementOnLine !== null + && $previousFontOnLine !== null + && SpaceDetector::shouldContainExtraSpace($positionedTextElement, $previousTextElementOnLine, $previousFontOnLine)) { + $textBuffer .= ' '; } $previousTextElementOnLine = $positionedTextElement; diff --git a/src/Extraction/SpaceDetection/SpaceDetector.php b/src/Extraction/SpaceDetection/SpaceDetector.php new file mode 100644 index 00000000..deefa4b4 --- /dev/null +++ b/src/Extraction/SpaceDetection/SpaceDetector.php @@ -0,0 +1,25 @@ +absoluteMatrix->offsetX + - $previousTextElementOnLine->absoluteMatrix->offsetX + - $previousTextElementOnLine->getAdvanceWidth($previousFontOnLine); + + $wordBreakThreshold = $previousTextElementOnLine->textState->getFontSize() + * $previousTextElementOnLine->absoluteMatrix->scaleX + * ($previousTextElementOnLine->textState->scale / 100) + * PositionedTextElement::WORD_BREAK_THRESHOLD_EM; + + return $gap >= $wordBreakThreshold; + } +} diff --git a/src/Extraction/TextExtractor.php b/src/Extraction/TextExtractor.php new file mode 100644 index 00000000..1ddba7ec --- /dev/null +++ b/src/Extraction/TextExtractor.php @@ -0,0 +1,54 @@ + $positionedTextElements + * @throws PdfParserException + */ + public static function extractContent(array $positionedTextElements, Page $page): string { + $lineGroupedElements = TextOverlapStrategy::group($positionedTextElements); + + $textBuffer = ''; + foreach ($lineGroupedElements as $i => $positionedTextElementsForLine) { + if ($i !== 0) { + $textBuffer .= "\n"; + } + + $previousTextElementOnLine = null; + $previousFontOnLine = null; + $previousTextElementEndsWithSpace = false; + foreach ($positionedTextElementsForLine as $positionedTextElement) { + $elementText = $positionedTextElement->getText($page); + $font = $positionedTextElement->getFont($page); + if ($elementText === '') { + $previousTextElementOnLine = $positionedTextElement; + $previousFontOnLine = $font; + continue; + } + + if ($previousTextElementEndsWithSpace === false + && str_starts_with($elementText, ' ') === false + && $previousTextElementOnLine !== null + && $previousFontOnLine !== null + && SpaceDetector::shouldContainExtraSpace($positionedTextElement, $previousTextElementOnLine, $previousFontOnLine)) { + $textBuffer .= ' '; + } + + $previousTextElementOnLine = $positionedTextElement; + $previousFontOnLine = $font; + $previousTextElementEndsWithSpace = str_ends_with($elementText, ' '); + $textBuffer .= $elementText; + } + } + + return $textBuffer; + } +} diff --git a/src/Extraction/Markdown/TextGrouping/LineGrouping/TextOverlapStrategy.php b/src/Extraction/TextGrouping/LineGrouping/TextOverlapStrategy.php similarity index 98% rename from src/Extraction/Markdown/TextGrouping/LineGrouping/TextOverlapStrategy.php rename to src/Extraction/TextGrouping/LineGrouping/TextOverlapStrategy.php index 41c5adf3..c48d58e4 100644 --- a/src/Extraction/Markdown/TextGrouping/LineGrouping/TextOverlapStrategy.php +++ b/src/Extraction/TextGrouping/LineGrouping/TextOverlapStrategy.php @@ -1,6 +1,6 @@ parseString( $fileContent, @@ -23,7 +23,7 @@ public function testParseStringInMemory(): void { public function testParseStringWithFileCache(): void { static::assertNotFalse($fileContent = file_get_contents(dirname(__DIR__) . '/Feature/samples/h3-simple-string.pdf')); static::assertSame( - ' Hello World ' . PHP_EOL, + ' Hello World ', (new PdfParser()) ->parseString( $fileContent, @@ -34,7 +34,7 @@ public function testParseStringWithFileCache(): void { public function testParseFileInMemory(): void { static::assertSame( - ' Hello World ' . PHP_EOL, + ' Hello World ', (new PdfParser()) ->parseFile( dirname(__DIR__) . '/Feature/samples/h3-simple-string.pdf', @@ -45,7 +45,7 @@ public function testParseFileInMemory(): void { public function testParseFileWithoutMemoryStream(): void { static::assertSame( - ' Hello World ' . PHP_EOL, + ' Hello World ', (new PdfParser()) ->parseFile( dirname(__DIR__) . '/Feature/samples/h3-simple-string.pdf',