Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/Document/Object/Decorator/Font.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PrinsFrank\PdfParser\Document\Object\Decorator;

use PrinsFrank\MarkDownDom\Enum\HeadingLevel;
use PrinsFrank\PdfParser\Document\CMap\Registry\RegistryOrchestrator;
use PrinsFrank\PdfParser\Document\CMap\ToUnicode\ToUnicodeCMap;
use PrinsFrank\PdfParser\Document\CMap\ToUnicode\ToUnicodeCMapParser;
Expand Down Expand Up @@ -312,4 +313,17 @@ public function isItalic(): bool {
|| str_contains($baseFont, 'oblique')
|| str_contains($baseFont, 'slanted');
}

public function getHeadingLevel(TextState $textState, TransformationMatrix $transformationMatrix): ?HeadingLevel {
$effectiveFontSize = $textState->getFontSize() * $transformationMatrix->scaleX;

return match (true) {
$effectiveFontSize >= 30 => HeadingLevel::Level1,
$effectiveFontSize >= 26 => HeadingLevel::Level2,
$effectiveFontSize >= 22 => HeadingLevel::Level3,
$effectiveFontSize >= 18 => HeadingLevel::Level4,
$effectiveFontSize >= 14 => HeadingLevel::Level5,
default => null,
};
}
}
62 changes: 45 additions & 17 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\BlockNode;
use PrinsFrank\MarkDownDom\Contract\InlineNode;
use PrinsFrank\MarkDownDom\Document;
use PrinsFrank\MarkDownDom\Enum\HeadingLevel;
use PrinsFrank\MarkDownDom\Node\Block\Heading;
use PrinsFrank\MarkDownDom\Node\Block\Paragraph;
use PrinsFrank\MarkDownDom\Node\Inline\Bold;
use PrinsFrank\MarkDownDom\Node\Inline\Italic;
Expand All @@ -21,14 +24,20 @@ class MarkdownExtractor {
public static function extractContent(array $positionedTextElements, Page $page): Document {
$lineGroupedElements = TextOverlapStrategy::group($positionedTextElements);

$lineNodes = [];
$blockNodes = $inLineNodes = [];
$textBuffer = '';
$previousElementIsBold = $previousElementIsItalic = false;
$previousHeadingLevel = null;
foreach ($lineGroupedElements as $i => $positionedTextElementsForLine) {
if ($i !== 0) {
if ($previousElementIsBold || $previousElementIsItalic) {
self::flushNodes($lineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
$lineNodes[] = new Text("\n");
if ($previousHeadingLevel !== null) {
self::flushInLineNodes($inLineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
self::flushBlockNodes($blockNodes, $inLineNodes, $previousHeadingLevel);
$previousHeadingLevel = null;
} elseif ($previousElementIsBold || $previousElementIsItalic) {
self::flushInLineNodes($inLineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
$inLineNodes[] = new Text("\n");
$previousElementIsItalic = $previousElementIsBold = false;
} else {
$textBuffer .= "\n";
}
Expand All @@ -44,9 +53,12 @@ public static function extractContent(array $positionedTextElements, Page $page)
}

$font = $positionedTextElement->getFont($page);
if ($font->isBold() !== $previousElementIsBold
|| $font->isItalic() !== $previousElementIsItalic) {
self::flushNodes($lineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
$currentHeadingLevel = $font->getHeadingLevel($positionedTextElement->textState, $positionedTextElement->absoluteMatrix);
if ($previousHeadingLevel !== $currentHeadingLevel) {
self::flushInLineNodes($inLineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
self::flushBlockNodes($blockNodes, $inLineNodes, $previousHeadingLevel);
} elseif ($font->isBold() !== $previousElementIsBold || $font->isItalic() !== $previousElementIsItalic) {
self::flushInLineNodes($inLineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
}

if ($previousTextElementOnLine !== null) {
Expand All @@ -72,25 +84,41 @@ public static function extractContent(array $positionedTextElements, Page $page)
$previousTextElementEndsWithSpace = str_ends_with($elementText, ' ');
$previousElementIsItalic = $font->isItalic();
$previousElementIsBold = $font->isBold();
$previousHeadingLevel = $currentHeadingLevel;
$textBuffer .= $elementText;
}
}

self::flushNodes($lineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
self::flushInLineNodes($inLineNodes, $textBuffer, $previousElementIsBold, $previousElementIsItalic);
self::flushBlockNodes($blockNodes, $inLineNodes, $previousHeadingLevel);

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

/** @param list<InlineNode> $lineNodes */
private static function flushNodes(array &$lineNodes, string &$textBuffer, bool $previousElementIsBold, bool $previousElementIsItalic): void {
/**
* @param list<BlockNode> $blockNodes
* @param list<InlineNode> $inLineNodes
*/
private static function flushBlockNodes(array &$blockNodes, array &$inLineNodes, ?HeadingLevel $previousHeadingLevel): void {
if ($previousHeadingLevel === null) {
$blockNodes[] = new Paragraph(...$inLineNodes);
} else {
$blockNodes[] = new Heading($previousHeadingLevel, ...$inLineNodes);
}

$inLineNodes = [];
}

/** @param list<InlineNode> $inLineNodes */
private static function flushInLineNodes(array &$inLineNodes, 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))));
$inLineNodes[] = new Text(substr($textBuffer, 0, strlen($textBuffer) - strlen(ltrim($textBuffer))));
$textBuffer = ltrim($textBuffer);
}
if (str_ends_with($textBuffer, ' ')) {
Expand All @@ -99,18 +127,18 @@ private static function flushNodes(array &$lineNodes, string &$textBuffer, bool
}
}

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

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

$lineNodes[] = $lineNode;
$inLineNodes[] = $inLineNode;
if ($trailingWhitespace !== null) {
$lineNodes[] = $trailingWhitespace;
$inLineNodes[] = $trailingWhitespace;
}
$textBuffer = '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,17 @@ 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.**
### **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 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
Expand Down
3 changes: 2 additions & 1 deletion tests/Samples/files/issue-152/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ pages:
NET A PAYER4 395,24EUR
SIRET : 43521016600011 - APE : 4634Z - TVA IntraCom : FR34435210166 - N° ACCISES : FR001513E0173
markdown: |-
**BERTOSSI & RAYNAL**
### **BERTOSSI & RAYNAL**

**Commande N° CF_007859**
SARL BERTOSSI-RAYNAL - PLAISIRS DU VIN
Allée de Riols - ZAC Agen Sud
Expand Down
6 changes: 4 additions & 2 deletions tests/Samples/files/issue-214/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ pages:
die Botschafterin von Barbados, Frau Nicolla Simone Rudder,
zur Entgegennahme ihrer Beglaubigungsschreiben empfangen.
markdown: |-
**Sonstiges**
##### **Sonstiges**

Veröffentlicht am Dienstag, 16. September 2025
BAnz AT 16.09.2025 S1
Seite 1 von 1
**Auswärtiges Amt**
##### **Auswärtiges Amt**

Empfänge beim Bundespräsidenten
Das Auswärtige Amt gibt bekannt:
Der Bundespräsident hat am Mittwoch, dem 27. August 2025
Expand Down
11 changes: 8 additions & 3 deletions tests/Samples/files/issue-215/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ modificationDate: 2025-09-01T16:24:09+02:00
pages:
-
text: |-
Deutscher Bundestag Drucksache 21/1407
Deutscher Bundestag
Drucksache 21/1407
21. Wahlperiode 28.08.2025
Antwort
der Bundesregierung
Expand Down Expand Up @@ -57,9 +58,13 @@ pages:
vom 28. August 2025 übermittelt.
Die Drucksache enthält zusätzlich – in kleinerer Schrifttype – den Fragetext.
markdown: |-
**Deutscher Bundestag Drucksache** 21/**1407**
##### **Deutscher Bundestag**

**Drucksache** ##### 21/**1407**

**21. Wahlperiode** 28.08.2025
**Antwort**
##### **Antwort**

**der Bundesregierung**
**auf die Kleine Anfrage der Abgeordneten Jörg Cezanne, Desiree Becker, Violetta**
**Bock, Clara Bünger, Anne-Mieke Bremer, Katrin Fey, Dr. Gregor Gysi, Luke Hoß,**
Expand Down
19 changes: 14 additions & 5 deletions tests/Samples/files/issue-235/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ pages:
-
text: |-

Niedersächsisches
Gesetz- und Verordnungsblatt
Niedersächsisches

Gesetz- und Verordnungsblatt

79. Jahrgang Hannover, den 10. April 2025 Nummer 25

Verordnung
Expand Down Expand Up @@ -49,9 +51,16 @@ pages:
Herausgeber: Niedersächsische Staatskanzlei
markdown: |2-
****
Niedersächsisches
Gesetz- und Verordnungsblatt
79. Jahrgang Hannover, den 10. April 2025 Nummer 25
#### Niedersächsisches

##

## Gesetz- und Verordnungsblatt

#

##### 79. Jahrgang Hannover, den 10. April 2025 Nummer 25


**Verordnung**
**zur Änderung der Feuerwehrverordnung**
Expand Down
3 changes: 2 additions & 1 deletion tests/Samples/files/issue-254/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ pages:
12.5.2021 DE Amtsblatt der Europäischen Union L 170/1
I
(Gesetzgebungsakte)
VERORDNUNGEN
##### VERORDNUNGEN

**VERORDNUNG (EU) 2021/695 DES EUROPÄISCHEN PARLAMENTS UND DES RATES**
**vom 28. April 2021**
**zur Einrichtung von „Horizont Europa“, dem Rahmenprogramm für Forschung und Innovation,**
Expand Down
30 changes: 20 additions & 10 deletions tests/Samples/files/issue-255/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,15 @@ pages:
– spezialisierte Beratung und Verweisberatung in den Fällen von Insolvenz, Trauer und so weiter,
– Rentenberatung zum Übergang am Ende des Berufslebens in die nachberufliche Phase.
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 1 von 8
**Bundesministerium**
**für Bildung, Familie, Senioren, Frauen und Jugend**
##### **Bundesministerium**

##### **für Bildung, Familie, Senioren, Frauen und Jugend**

Förderrichtlinie
„Zusammenhalt stärken – Menschen verbinden“
ESF Plus-Förderperiode 2021 bis 2027
Expand Down Expand Up @@ -189,7 +192,8 @@ pages:
periode 2021 bis 2027 (BNBest-P-ESF-Bund) sowie den Besonderen Nebenbestimmungen für Zuwendungen zur
Projektförderung an Gebietskörperschaften und Zusammenschlüsse von Gebietskörperschaften im Rahmen des
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 2 von 8
Expand Down Expand Up @@ -310,7 +314,8 @@ pages:
zweckentsprechende Verwendung der von ihm weitergeleiteten Mittel durch den/die Teilvorhabenpartner verantwort-
lich.
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 3 von 8
Expand Down Expand Up @@ -425,7 +430,8 @@ pages:
aufbringen.
Die Zuschusshöhe beträgt pro Vorhaben und Jahr mindestens 20 000 Euro und höchstens 150 000 Euro.
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 4 von 8
Expand Down Expand Up @@ -546,7 +552,8 @@ pages:
bindung mit Artikel 6 der Verordnung (EU) 2021/1057 die bereichsübergreifenden Grundsätze Gleichstellung der
Geschlechter und der Antidiskriminierung unter Hinzunahme des Ziels der ökologischen Nachhaltigkeit integriert
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 5 von 8
Expand Down Expand Up @@ -669,7 +676,8 @@ pages:
gen. Um den geltenden Datenschutzvorschriften zu genügen, müssen die Vorgaben der Verwaltungsbehörde zur
Erfüllung der Informationspflicht nach Artikel 14 der Datenschutz-Grundverordnung umgesetzt werden.
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 6 von 8
Expand Down Expand Up @@ -790,7 +798,8 @@ pages:
Verwaltungsvorschriften, soweit nicht in diesen Förderrichtlinien Abweichungen von den Allgemeinen Verwaltungs-
vorschriften zugelassen worden sind.
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 7 von 8
Expand Down Expand Up @@ -870,7 +879,8 @@ pages:
Im Auftrag
Beate Brinkmann
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 1. Oktober 2025
BAnz AT 01.10.2025 B1
Seite 8 von 8
Expand Down
6 changes: 4 additions & 2 deletions tests/Samples/files/issue-272/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ pages:
Der Vorsitzende
Prof. Hecken
markdown: |-
**Bekanntmachung**
##### **Bekanntmachung**

Veröffentlicht am Mittwoch, 8. Oktober 2025
BAnz AT 08.10.2025 B5
Seite 1 von 1
**Bundesministerium für Gesundheit**
##### **Bundesministerium für Gesundheit**

Bekanntmachung
eines Beschlusses des Gemeinsamen Bundesausschusses
über eine Änderung der MD-Qualitätskontroll-Richtlinie:
Expand Down
11 changes: 8 additions & 3 deletions tests/Samples/files/issue-290/contents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ modificationDate: 2025-09-12T14:25:52+02:00
pages:
-
text: |-
Deutscher Bundestag Drucksache 21/1576
Deutscher Bundestag
Drucksache 21/1576
21. Wahlperiode 10.09.2025
Antwort
der Bundesregierung
Expand Down Expand Up @@ -55,9 +56,13 @@ pages:
vom 9. September 2025 übermittelt.
Die Drucksache enthält zusätzlich – in kleinerer Schrifttype – den Fragetext.
markdown: |-
**Deutscher Bundestag Drucksache** 21/**1576**
##### **Deutscher Bundestag**

**Drucksache** ##### 21/**1576**

**21. Wahlperiode** 10.09.2025
**Antwort**
##### **Antwort**

**der Bundesregierung**
**auf die Kleine Anfrage der Abgeordneten Bodo Ramelow, Clara Bünger, Anne-**
**Mieke Bremer, weiterer Abgeordneter und der Fraktion Die Linke**
Expand Down
Loading
Loading