Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ public function getHeight(): float {
*
* Reconstructed here because Tj/TJ do not advance the text matrix in this parser.
*/
public function getAdvanceWidth(Page $page): float {
$font = $this->getFont($page);
public function getAdvanceWidth(Font $font): float {
$scaleX = $this->absoluteMatrix->scaleX;
$fontSize = $this->textState->getFontSize();

Expand Down
24 changes: 24 additions & 0 deletions src/Document/Object/Decorator/Font.php
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,28 @@ public function getFontDescriptor(): ?ReferenceValue {
return $this->getDictionary()
->getValueForKey($this->document, DictionaryKey::FONT_DESCRIPTOR, ReferenceValue::class);
}

public function isBold(): bool {
$baseFont = $this->getBaseFont();
if ($baseFont === null) {
return false;
}

$baseFont = strtolower($baseFont);
return str_contains($baseFont, 'bold')
|| str_contains($baseFont, 'heavy')
|| str_contains($baseFont, 'black');
}

public function isItalic(): bool {
$baseFont = $this->getBaseFont();
if ($baseFont === null) {
return false;
}

$baseFont = strtolower($baseFont);
return str_contains($baseFont, 'italic')
|| str_contains($baseFont, 'oblique')
|| str_contains($baseFont, 'slanted');
}
}
70 changes: 63 additions & 7 deletions src/Extraction/Markdown/MarkdownExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

namespace PrinsFrank\PdfParser\Extraction\Markdown;

use PrinsFrank\MarkDownDom\Contract\InlineNode;
use PrinsFrank\MarkDownDom\Document;
use PrinsFrank\MarkDownDom\Node\Block\Paragraph;
use PrinsFrank\MarkDownDom\Node\Inline\Bold;
use PrinsFrank\MarkDownDom\Node\Inline\Italic;
use PrinsFrank\MarkDownDom\Node\Inline\Text;
use PrinsFrank\PdfParser\Document\ContentStream\PositionedText\PositionedTextElement;
use PrinsFrank\PdfParser\Document\Object\Decorator\Page;
Expand All @@ -18,24 +21,38 @@ class MarkdownExtractor {
public static function extractContent(array $positionedTextElements, Page $page): Document {
$lineGroupedElements = TextOverlapStrategy::group($positionedTextElements);

$text = '';
$lineNodes = [];
$textBuffer = '';
$previousElementIsBold = $previousElementIsItalic = false;
foreach ($lineGroupedElements as $i => $positionedTextElementsForLine) {
if ($i !== 0) {
$text .= "\n";
if ($previousElementIsBold || $previousElementIsItalic) {
self::flushNodes($lineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
$lineNodes[] = new Text("\n");
} else {
$textBuffer .= "\n";
}
}

$previousTextElementOnLine = null;
$previousTextElementEndsWithSpace = false;
foreach ($positionedTextElementsForLine as $positionedTextElement) {
$elementText = $positionedTextElement->getText($page);
if ($elementText === '') {
$previousTextElementOnLine = $positionedTextElement;
continue;
}

$font = $positionedTextElement->getFont($page);
if ($font->isBold() !== $previousElementIsBold
|| $font->isItalic() !== $previousElementIsItalic) {
self::flushNodes($lineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
}

if ($previousTextElementOnLine !== null) {
$gap = $positionedTextElement->absoluteMatrix->offsetX
- $previousTextElementOnLine->absoluteMatrix->offsetX
- $previousTextElementOnLine->getAdvanceWidth($page);
- $previousTextElementOnLine->getAdvanceWidth($font);

$wordBreakThreshold = $previousTextElementOnLine->textState->getFontSize()
* $previousTextElementOnLine->absoluteMatrix->scaleX
Expand All @@ -44,18 +61,57 @@ public static function extractContent(array $positionedTextElements, Page $page)

if (
$gap >= $wordBreakThreshold
&& str_ends_with($text, ' ') === false
&& $previousTextElementEndsWithSpace === false
&& str_starts_with($elementText, ' ') === false
) {
$text .= ' ';
$textBuffer .= ' ';
}
}

$text .= $elementText;
$previousTextElementOnLine = $positionedTextElement;
$previousTextElementEndsWithSpace = str_ends_with($elementText, ' ');
$previousElementIsItalic = $font->isItalic();
$previousElementIsBold = $font->isBold();
$textBuffer .= $elementText;
}
}

return new Document(new Paragraph(new Text($text)));
self::flushNodes($lineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);

return new Document(new Paragraph(...$lineNodes));
}

/** @param list<InlineNode> $lineNodes */
private static function flushNodes(array &$lineNodes, string &$textBuffer, bool $previousElementIsBold, bool $previousElementIsItalic): void {
if ($textBuffer === '') {
return;
}

$trailingWhitespace = null;
if ($previousElementIsBold || $previousElementIsItalic) {
if (str_starts_with($textBuffer, ' ')) {
$lineNodes[] = new Text(substr($textBuffer, 0, strlen($textBuffer) - strlen(ltrim($textBuffer))));
$textBuffer = ltrim($textBuffer);
}
if (str_ends_with($textBuffer, ' ')) {
$trailingWhitespace = new Text(substr($textBuffer, strlen(rtrim($textBuffer))));
$textBuffer = rtrim($textBuffer);
}
}

$lineNode = new Text($textBuffer);
if ($previousElementIsBold) {
$lineNode = new Bold($lineNode);
}

if ($previousElementIsItalic) {
$lineNode = new Italic($lineNode);
}

$lineNodes[] = $lineNode;
if ($trailingWhitespace !== null) {
$lineNodes[] = $trailingWhitespace;
}
$textBuffer = '';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ pages:
aperiam.
Lorem ipsum dolor sit amet. Et omnis perferendis Et quisquam qui laboriosam explicabo et
natus corrupti aut repudiandae iure quo inventore itaque et odio atque. Qui necessitatibus
odit et commodi accusamus Et fuga!
odit et commodi accusamusEt fuga!
Qui distinctio praesentium sed corporis reiciendis eum
molestiae eius.
Qui aperiam aspernatur rem consectetur ullamest quod qui architecto corporis et
repellendus expedita! Ex fuga ducimus Ea ipsam et nobis architecto sed ratione deserunt et
iure sapiente qui animi Quis. Cum quod facilis eos exercitationem quam Est ullam est
galisum assumenda cum distinctio tempora qui quasi rerum et pariatur harum.
Est incidunt repellat aut iusto odit.
Et magnam incidunt eum possimus perspiciatis Quo pariatur aut perferendis laboriosam
Et magnam incidunt eum possimus perspiciatisQuo pariatur aut perferendis laboriosam
eum repellat ipsa ut debitis ipsa ut distinctio dolores! Et rerum expeditaAut ullam ad ullam
deleniti est facilis consequatur ut architecto nobis.
Non debitis expedita ea reprehenderit asperiores et voluptatem quos.
Expand All @@ -34,7 +34,7 @@ pages:
soluta nulla in culpa iure et quia recusandae? Qui veniam quia id maiores excepturiQui
dolores et officia aperiam ab sint excepturi.
Est molestias illum est dolorem praesentium cum soluta nesciunt.
Ut velit aspernatur ut earum debitis Qui ullam aut quod dolorum quo molestiae magni et
Ut velit aspernatur ut earum debitisQui ullam aut quod dolorum quo molestiae magni et
corrupti minima. Id dolor error ab dignissimos corporis Quo commodi. Et soluta doloribus
Eos quae in magnam praesentium aut accusantium laboriosam non nemo reprehenderit.
Et eveniet ducimus Ut voluptatem et porro velit id suscipit impedit! Vel culpa itaque Eos fuga
Expand All @@ -45,36 +45,36 @@ pages:
eos doloribus autem vel accusamus sequi et quidem reiciendis.
● Ut autem excepturi ut sequi laboriosam est quas debitis et placeat consequatur!
markdown: |-
Nam quod molestias vel corporis
aperiam.
Lorem ipsum dolor sit amet. Et omnis perferendis Et quisquam qui laboriosam explicabo et
natus corrupti aut repudiandae iure quo inventore itaque et odio atque. Qui necessitatibus
odit et commodi accusamus Et fuga!
Qui distinctio praesentium sed corporis reiciendis eum
molestiae eius.
**Nam quod molestias vel corporis**
**aperiam.**
Lorem ipsum dolor sit amet. Et omnis perferendis *Et quisquam qui laboriosam explicabo et*
*natus corrupti* aut repudiandae iure quo inventore itaque et odio atque. Qui necessitatibus
odit et commodi accusamus**Et fuga**!
**Qui distinctio praesentium sed corporis reiciendis eum**
**molestiae eius.**
Qui aperiam aspernatur rem consectetur ullamest quod qui architecto corporis et
repellendus expedita! Ex fuga ducimus Ea ipsam et nobis architecto sed ratione deserunt et
repellendus expedita! Ex fuga ducimus *Ea ipsam et nobis architecto sed ratione deserunt* et
iure sapiente qui animi Quis. Cum quod facilis eos exercitationem quam Est ullam est
galisum assumenda cum distinctio tempora qui quasi rerum et pariatur harum.
Est incidunt repellat aut iusto odit.
Et magnam incidunt eum possimus perspiciatis Quo pariatur aut perferendis laboriosam
eum repellat ipsa ut debitis ipsa ut distinctio dolores! Et rerum expeditaAut ullam ad ullam
**Est incidunt repellat aut iusto odit.**
Et magnam incidunt eum possimus perspiciatis**Quo pariatur aut perferendis laboriosam**
**eum repellat ipsa ut debitis ipsa** ut distinctio dolores! Et rerum expeditaAut ullam ad ullam
deleniti est facilis consequatur ut architecto nobis.
Non debitis expedita ea reprehenderit asperiores et voluptatem quos.
Non minima soluta Sed delectus qui repellendus dolorem et galisum quia. Non sunt debitis
**Non debitis expedita ea reprehenderit asperiores et voluptatem quos.**
Non minima soluta *Sed delectus* qui repellendus dolorem et galisum quia. Non sunt debitis
ab vitae aspernatur Ex minus eum optio assumenda est voluptatem illum et harum ipsam
rem veniam culpa. Aut adipisci deserunt non inventore ratione Hic iste vel sint unde non
soluta nulla in culpa iure et quia recusandae? Qui veniam quia id maiores excepturiQui
rem veniam culpa. Aut adipisci deserunt non inventore ratione **Hic iste vel sint unde non**
**soluta nulla in culpa iure** et quia recusandae? Qui veniam quia id maiores excepturiQui
dolores et officia aperiam ab sint excepturi.
Est molestias illum est dolorem praesentium cum soluta nesciunt.
Ut velit aspernatur ut earum debitis Qui ullam aut quod dolorum quo molestiae magni et
corrupti minima. Id dolor error ab dignissimos corporis Quo commodi. Et soluta doloribus
**Est molestias illum est dolorem praesentium cum soluta nesciunt.**
Ut velit aspernatur ut earum debitis**Qui ullam aut quod dolorum quo molestiae magni et**
**corrupti minima**. Id dolor error ab dignissimos corporis *Quo commodi*. Et soluta doloribus
Eos quae in magnam praesentium aut accusantium laboriosam non nemo reprehenderit.
Et eveniet ducimus Ut voluptatem et porro velit id suscipit impedit! Vel culpa itaque Eos fuga
aut totam laudantium qui eveniet molestiae vel dolores fugiat.
Est saepe soluta et vero voluptatemQuo maxime! Eos tempora quas ad nesciunt itaque Ea
nihil et ullam repellat et voluptatem delectus. Aut voluptatum pariatur Id molestias cum
nobis molestias. Ut velit distinctioEx consectetur eos debitis perspiciatis a minus commodi
Et eveniet ducimus *Ut voluptatem et porro velit id suscipit impedit*! Vel culpa itaque **Eos fuga**
**aut totam laudantium qui eveniet molestiae vel dolores fugiat**.
Est saepe soluta et vero voluptatemQuo maxime! Eos tempora quas ad nesciunt itaque **Ea**
**nihil et ullam repellat et voluptatem delectus**. Aut voluptatum pariatur *Id molestias cum*
*nobis molestias*. Ut velit distinctioEx consectetur eos debitis perspiciatis a minus commodi
eos doloribus autem vel accusamus sequi et quidem reiciendis.
● Ut autem excepturi ut sequi laboriosam est quas debitis et placeat consequatur!
-
Expand All @@ -85,7 +85,7 @@ pages:
● At adipisci enim id reiciendis officiis.
● Sed sapiente quia qui sint dolorem vel impedit magni.
Et dicta voluptatem sit fugit saepevel nulla et debitis iure et ipsa voluptas? Est facere harum
et inventore eveniet Aut rerum est molestias quam qui perspiciatis magnam.
et inventore evenietAut rerum est molestias quam qui perspiciatis magnam.
Qui eligendi saepe et neque autem A omnis et pariatur rerum est dolore rerum est facere
quasi. Sit dolorem quiaet veritatis rem alias deleniti. Et voluptatem laborum et impedit
atqueaut suscipit. Rem unde quos cum reprehenderit temporeQui eaque sit rerum distinctio
Expand All @@ -105,15 +105,15 @@ pages:
● At adipisci enim id reiciendis officiis.
● Sed sapiente quia qui sint dolorem vel impedit magni.
Et dicta voluptatem sit fugit saepevel nulla et debitis iure et ipsa voluptas? Est facere harum
et inventore eveniet Aut rerum est molestias quam qui perspiciatis magnam.
Qui eligendi saepe et neque autem A omnis et pariatur rerum est dolore rerum est facere
quasi. Sit dolorem quiaet veritatis rem alias deleniti. Et voluptatem laborum et impedit
et inventore eveniet**Aut rerum est molestias quam qui perspiciatis magnam**.
Qui eligendi saepe et neque autem *A omnis et pariatur rerum est dolore rerum est facere*
*quasi*. Sit dolorem quiaet veritatis rem alias deleniti. Et voluptatem laborum et impedit
atqueaut suscipit. Rem unde quos cum reprehenderit temporeQui eaque sit rerum distinctio
ut ipsam culpa ab error sunt et quaerat Quis.
In recusandae dolor id laudantium omnisaut velit aut perferendis omnis qui tenetur
explicabo. Et maxime assumenda et ipsam itaqueAut deleniti ut excepturi alias et fugit
facere non modi laudantium. Qui sapiente rerum non sunt ipsum Ad maxime est velit
eligendi aut quaerat officia est architecto magnam?
facere non modi laudantium. Qui sapiente rerum non sunt ipsum *Ad maxime est velit*
*eligendi aut quaerat officia est architecto magnam*?
1. Et sequi ipsum et expedita ipsum eum dolore laborum.
2. Id enim unde eos commodi quidem et eius quaerat.
3. Est tempore veritatis sed aliquam Quis.
Expand Down
Loading
Loading