Skip to content

Commit c9d0af9

Browse files
committed
Keep enclosed subscripts on their text line
A smaller glyph whose baseline is shifted off the line, such as the "2" in "CO2", overlaps the line too little to clear the line-overlap threshold and ended up on a line of its own. When such an element partially overlaps the line and sits horizontally within the run already collected, it is enclosed by surrounding text and belongs to that line. A smaller element that merely sits close but is not enclosed, like a subtitle beside a heading, keeps its own line.
1 parent 69f18a9 commit c9d0af9

5 files changed

Lines changed: 51 additions & 17 deletions

File tree

src/Document/ContentStream/PositionedText/LineGroupingStrategy/TextOverlapStrategy.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public function group(array $positionedTextElements): iterable {
4848

4949
$positionedTextElementsOnLine = [$highestPositionedTextElement];
5050
$processedIndices[$i] = true;
51+
$lineLeftX = $highestPositionedTextElement->absoluteMatrix->offsetX;
52+
$lineRightX = $highestPositionedTextElement->absoluteMatrix->offsetX;
5153
for ($j = $i + 1; $j < $nrOfItems; $j++) {
5254
if (isset($processedIndices[$j])) {
5355
continue;
@@ -63,9 +65,22 @@ public function group(array $positionedTextElements): iterable {
6365

6466
$overlap = min($highestElementTop, $currentElementTop) - max($highestPositionedTextElementBottom, $currentElementBottom);
6567
$smallestElementHeight = min($positionedTextElementHeight, $highestPositionedTextElementHeight);
66-
if ($smallestElementHeight !== 0.0 && $overlap / $smallestElementHeight * 100 >= $this->overlapPercentage) {
68+
if ($smallestElementHeight === 0.0) {
69+
continue;
70+
}
71+
72+
$belongsOnLine = $overlap / $smallestElementHeight * 100 >= $this->overlapPercentage;
73+
74+
$isEnclosedSubscript = $overlap > 0.0
75+
&& $positionedTextElementHeight < $highestPositionedTextElementHeight
76+
&& $positionedTextElement->absoluteMatrix->offsetX >= $lineLeftX
77+
&& $positionedTextElement->absoluteMatrix->offsetX <= $lineRightX;
78+
79+
if ($belongsOnLine || $isEnclosedSubscript) {
6780
$positionedTextElementsOnLine[] = $positionedTextElement;
6881
$processedIndices[$j] = true;
82+
$lineLeftX = min($lineLeftX, $positionedTextElement->absoluteMatrix->offsetX);
83+
$lineRightX = max($lineRightX, $positionedTextElement->absoluteMatrix->offsetX);
6984
}
7085
}
7186

tests/Samples/files/issue-127/contents.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,7 @@ pages:
479479
davon Kassenkredite 973.606 169.622 187.393 25.376 591.215 6.398 644.427 1.754.857 509.372 375.948 50.464 819.072 g g +80,2 +200,3 +100,6 +98,9 +38,5 x x
480480
davon Wertpapierschulden u. Kredite 14.155.560 3.236.587 2.031.803 1.057.262 7.829.909 1.616.176 15.399.208 15.723.382 3.701.622 2.178.372 1.148.446 8.694.942 g g +11,1 +14,4 +7,2 +8,6 +11,0 x x
481481
1)
482-
Schulden beim öffentlichen Bereich 961.509 74.851 14.424 73.031 799.203 1.792.088 4.475.428 1.214.517 93.984 13.024 48.468 1.059.041 g g +26,3 +25,6 -9,7 -33,6 +32,5 x x
483-
1)
482+
Schulden beim öffentlichen Bereich1) 961.509 74.851 14.424 73.031 799.203 1.792.088 4.475.428 1.214.517 93.984 13.024 48.468 1.059.041 g g +26,3 +25,6 -9,7 -33,6 +32,5 x x
484483
davon Kassenkredite 443.012 23.973 2.064 28.936 388.038 32.928 203.824 586.893 48.750 2.064 3.487 532.591 g g +32,5 +103,4 +0,0 -87,9 +37,3 x x
485484
davon Kredite 518.498 50.878 12.360 44.095 411.165 1.759.160 4.271.604 627.624 45.234 10.960 44.981 526.450 g g +21,0 -11,1 -11,3 +2,0 +28,0 x x
486485
1)

tests/Samples/files/issue-215/contents.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,7 @@ pages:
253253
30. Welche Auswirkungen könnte die geplante Bodenversiegelung auf das
254254
lokale Klima und die Luftqualität haben?
255255
31. Welche Maßnahmen hält die Bundesregierung für notwendig, um negati-
256-
ve klimatische Effekte, wie eine Verschlechterung der CO -Bilanz oder
257-
2
256+
ve klimatische Effekte, wie eine Verschlechterung der CO2-Bilanz oder
258257
die Entstehung von städtischen Hitzeinseln, durch das Bauprojekt zu ver-
259258
hindern oder zu minimieren?
260259
32. Welche Maßnahmen sind vorgesehen, um insbesondere die Folgen von

tests/Samples/files/issue-254/contents.yml

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,16 +2584,14 @@ pages:
25842584
Interventionsbereiche: katastrophenresiliente Gesellschaft; Schutz und Sicherheit; Cycherheit.
25852585
d)Cluster „Digitalisierung, Industrie und Weltraum“: Stärkung der Kapazitäten und Sicherung der Souveränität Europas
25862586
in für Digitalisierung und Produktion wichtigen Schlüsseltechnologien sowie in der Weltraumtechnologie, entlang
2587-
der gesamten Wertschöpfungskette, mit Blick auf den Aufbau einer wettbewerbsfähigen, digitalen, CO-armen und
2588-
2
2587+
der gesamten Wertschöpfungskette, mit Blick auf den Aufbau einer wettbewerbsfähigen, digitalen, CO2-armen und
25892588
kreislauforientierten Industrie; Sicherung einer nachhaltigen Rohstoffversorgung; Entwicklung fortgeschrittener
25902589
Werkstoffe und Bereitstellung der Grundlage für Fortschritt und Innovation im Bereich der globalen
25912590
gesellschaftlichen Herausforderungen.
25922591
Interventionsbereiche: Herstellungsverfahren; digitale Schlüsseltechnologien, einschließlich Quantentechnologien;
25932592
neue Grundlagentechnologien; fortgeschrittene Werkstoffe; künstliche Intelligenz und Robotik; Internet der
25942593
nächsten Generation; fortgeschrittene Rechensy und Massendatenverarbeitung (Big Data); kreislauforientierte
2595-
Industrie; CO-arme und saubere Industrien; Weltraumtätigkeiten, einschließlich Erdbeobachtung.
2596-
2
2594+
Industrie; CO2-arme und saubere Industrien; Weltraumtätigkeiten, einschließlich Erdbeobachtung.
25972595
e) Cluster „Klima, Energie und Mobilität“: Bekämpfung des Klimawandels, indem bessere Kenntnisse über dessen
25982596
Ursachen und Verlauf, Risiken, Auswirkungen und Chancen erlangt, die Sektoren Energie und Verkehr klima- und
25992597
umweltfreundlicher, effizienter und wettbewerbsfähiger, intelligenter, sicherer und tragfähiger gemacht, die Nutzung
@@ -2607,8 +2605,7 @@ pages:
26072605
f) Cluster „Lebensmittel, Bioökonomie, natürliche Ressourcen, Landwirtschaft und Umwelt“: Umweltschutz,
26082606
Wiederherstellung, nachhaltige Bewirtschaftung und Nutzung der natürlichen und biologischen Land-,
26092607
Binnengewässer- und Meeresressourcen zur Beendigung der Erosion der biologischen Vielfalt sowie zur Sicherung
2610-
der Nahrungsmittel- und Nährstoffversorgung für alle und des Übergangs zu einer CO-armen und ressourcenef­
2611-
2
2608+
der Nahrungsmittel- und Nährstoffversorgung für alle und des Übergangs zu einer CO2-armen und ressourcenef­
26122609
fizienten Kreislaufwirtschaft und einer nachhaltigen Bioökonomie.
26132610
-
26142611
content: |-
@@ -3132,13 +3129,10 @@ pages:
31323129
können.
31333130
15.Durch Sy mit dem Innovationsfonds im Rahmen des Emissionshandelssytems (im Folgenden
31343131
„Innovationsfonds“) wird Folgendes sichergestellt:
3135-
a) Der Innovationsfonds ist gezielt auf Innovationen im Bereich CO-arme Technologien und Prozesse ausgerichtet,
3136-
2
3137-
darunter umweltverträgliche CO-Abscheidung und -Nutzung, die erheblich zur Eindämmung des Klimawandels
3138-
2
3132+
a) Der Innovationsfonds ist gezielt auf Innovationen im Bereich CO2-arme Technologien und Prozesse ausgerichtet,
3133+
darunter umweltverträgliche CO2-Abscheidung und -Nutzung, die erheblich zur Eindämmung des Klimawandels
31393134
beitragen, sowie Produkte, die kohlenstoffintensive Produkte ersetzen, und soll die Gestaltung und Umsetzung von
3140-
Projekten, die auf eine umweltverträgliche Abscheidung und geologische Speicherung von CO abzielen, und
3141-
2
3135+
Projekten, die auf eine umweltverträgliche Abscheidung und geologische Speicherung von CO2 abzielen, und
31423136
innovative Technologien für erneuerbare Energien und Energiespeicherung anregen sowie umweltfreundlichere
31433137
Produkte ermöglichen und Anreize dafür schaffen;
31443138
b)mit dem Programm werden Mittel für die Entwicklung und Demonstration von Technologien, einschließlich

tests/Unit/Document/ContentStream/PositionedText/LineGroupingStrategy/TextOverlapStrategyTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,31 @@ public function testOrdersLinesTopToBottomOnANegativeOriginPage(): void {
3434
iterator_to_array((new TextOverlapStrategy())->group([$bottom, $top]), false),
3535
);
3636
}
37+
38+
public function testKeepsAnEnclosedSubscriptOnItsLine(): void {
39+
// A subscript like the "2" in "CO2" has a smaller font and a baseline shifted down, so it overlaps the line
40+
// too little to clear the threshold on its own. Because it is enclosed horizontally by text on the line
41+
// ("CO" before it, "-Bilanz" after it) it still belongs to that line rather than forming a line of its own.
42+
$left = new PositionedTextElement('(CO)', new TransformationMatrix(1, 0, 0, 1, 50, 100), new TextState(null, 10));
43+
$subscript = new PositionedTextElement('(2)', new TransformationMatrix(1, 0, 0, 1, 60, 98), new TextState(null, 7));
44+
$right = new PositionedTextElement('(-Bilanz)', new TransformationMatrix(1, 0, 0, 1, 70, 100), new TextState(null, 10));
45+
46+
static::assertSame(
47+
[[$left, $subscript, $right]],
48+
iterator_to_array((new TextOverlapStrategy())->group([$left, $right, $subscript]), false),
49+
);
50+
}
51+
52+
public function testKeepsASmallerButNotEnclosedLineSeparate(): void {
53+
// A smaller line that merely sits close (e.g. a subtitle below a heading) overlaps the heading just as much
54+
// as an enclosed subscript would, but it is not enclosed horizontally by the heading's text, so it must keep
55+
// its own line instead of being absorbed.
56+
$heading = new PositionedTextElement('(BERTOSSI)', new TransformationMatrix(1, 0, 0, 1, 20, 800), new TextState(null, 22));
57+
$subtitle = new PositionedTextElement('(Commande)', new TransformationMatrix(1, 0, 0, 1, 200, 796), new TextState(null, 12));
58+
59+
static::assertSame(
60+
[[$heading], [$subtitle]],
61+
iterator_to_array((new TextOverlapStrategy())->group([$subtitle, $heading]), false),
62+
);
63+
}
3764
}

0 commit comments

Comments
 (0)