fix(pptx): filter off-slide shapes by how much of the box is visible

Merged
FE
2d ago
+127-3

Summary

partition_pptx decides whether a shape is off-slide by looking only at a negative top-left corner, and only when both coordinates are non-zero. That drops shapes that are mostly visible but nudge past an edge, keeps shapes parked to the right of or below the slide, and misses the zero-coordinate case entirely (left=0, top=-2 is processed). It also ties the answer to the origin rather than to the box.

This switches the check to visible area: a shape is off-slide when less than half of its box overlaps the slide. A shape with no position is still treated as top-left and on-slide. include_off_slide_shapes: bool = False on partition_pptx skips the check entirely for callers that need hidden text (compliance or archival search); it is threaded through PptxPartitionerOptions next to include_slide_notes, and partition_ppt forwards kwargs so it inherits the flag.

The 50% threshold matches "only extract text the audience can see"; an any-overlap rule would keep slivers of off-slide text. Group shapes report positions relative to the group, so this check can still misjudge them; that is out of scope here, as noted in the review.

Validation

pytest test_unstructured/partition/test_pptx.py → 78 passed. At 8150372f, the new tests fail: the zero-coordinate cases leak, the right/bottom-parked boxes are included, and include_off_slide_shapes=True is dropped by **kwargs while the default run includes the parked shape. The partly-visible box at left=-0.1in, top=0 is included; base only included it because top=0 trips the "no position" shortcut, which is the same leak this PR closes.

ruff check and ruff format --check pass on both files.

Release note (optional)

PPTX shapes are now filtered by how much of their box overlaps the slide rather than by a negative top-left corner. Text from mostly-visible shapes at a slide edge is kept, text from shapes that are mostly off the slide is dropped, and partition_pptx(..., include_off_slide_shapes=True) restores the include-everything behavior for callers that need it.

Checklist

  • The PR title is a user-facing release-note entry with a conventional commit prefix.
  • Category label: bug (maintainer to apply).
  • Behavior change is gated: fully on-slide shapes are unchanged, mostly-visible shapes at an edge are now kept, and include_off_slide_shapes=True opts out of the check.