fix: keep layout superscripts aligned with baseline numbers - #1392
BetterAndBetterII wants to merge 1 commit into
Conversation
layout=True clustered superscript '*' just above a baseline number onto its own line, leaving raw x-columns while the baseline drifted right so the markers appeared shifted left. Widen line clustering for layout and x-sort layout lines so annotated markers stay after their numbers. Fixes jsvine#1380
|
I reproduced a regression on head The test below uses 4-point characters on rows 5 points apart, leaving a 1-point vertical gap. It returns At default Could the superscript handling preserve the caller's ability to keep distinct rows separate? This regression test needs no additional dependency beyond pytest and the library: """Regression coverage for pdfplumber PR 1392; no additional dependency."""
import pytest
from pdfplumber import utils
def make_char(text, x0, top):
return {
"text": text,
"x0": x0,
"x1": x0 + 2,
"top": top,
"doctop": top,
"bottom": top + 4,
"width": 2,
"height": 4,
"size": 4,
"upright": True,
}
@pytest.mark.parametrize("use_text_flow", [False, True])
@pytest.mark.parametrize("y_tolerance", [0, 3])
def test_layout_preserves_separate_nonoverlapping_rows(use_text_flow, y_tolerance):
chars = [
make_char(letter, 30 + 2 * index, top)
for word, top in [("Alpha", 100), ("Beta", 105)]
for index, letter in enumerate(word)
]
text = utils.extract_text(
chars,
layout=True,
layout_bbox=(0, 0, 200, 200),
layout_width=200,
layout_height=200,
use_text_flow=use_text_flow,
y_tolerance=y_tolerance,
)
assert [line.strip() for line in text.splitlines() if line.strip()] == [
"Alpha",
"Beta",
]I also ran the existing Candidate amendment: patch and reproduction notes. This experimental amendment applies to head |
Summary
With
extract_text(layout=True), a superscript*sitting just above a baseline number (common footnote / citation markers) was clustered onto its own layout line. That line kept raw PDF x-columns while the baseline line drifted right, so the markers appeared shifted left of328/329(issue PDF: Against Celsus line).Two small layout-only adjustments:
layout=Truewithmax(y_tolerance, line_density / 2)so near-baseline superscripts share a line with the text they annotate.presorted=True, so extraction order cannot leave*before the number it belongs to.use_text_flowis unchanged.Test plan
pytest tests/test_utils.py(37 passed), including new synthetic superscript layout regressionpage826.pdf: one lineAgainst Celsus (Origen), 327 , 328 * , 329 *Fixes #1380