Extract text content from all slides in a PowerPoint presentation. Args: pptx_path: Path to the PowerPoint file prs: Optional Presentation object to use. If not provided, will load from pptx_path. issues_only: If True, only include shapes that have overflow or overlap is
(
pptx_path: Path, prs: Optional[Any] = None, issues_only: bool = False
)
| 912 | |
| 913 | |
| 914 | def extract_text_inventory( |
| 915 | pptx_path: Path, prs: Optional[Any] = None, issues_only: bool = False |
| 916 | ) -> InventoryData: |
| 917 | """Extract text content from all slides in a PowerPoint presentation. |
| 918 | |
| 919 | Args: |
| 920 | pptx_path: Path to the PowerPoint file |
| 921 | prs: Optional Presentation object to use. If not provided, will load from pptx_path. |
| 922 | issues_only: If True, only include shapes that have overflow or overlap issues |
| 923 | |
| 924 | Returns a nested dictionary: {slide-N: {shape-N: ShapeData}} |
| 925 | Shapes are sorted by visual position (top-to-bottom, left-to-right). |
| 926 | The ShapeData objects contain the full shape information and can be |
| 927 | converted to dictionaries for JSON serialization using to_dict(). |
| 928 | """ |
| 929 | if prs is None: |
| 930 | prs = Presentation(str(pptx_path)) |
| 931 | inventory: InventoryData = {} |
| 932 | |
| 933 | for slide_idx, slide in enumerate(prs.slides): |
| 934 | # Collect all valid shapes from this slide with absolute positions |
| 935 | shapes_with_positions = [] |
| 936 | for shape in slide.shapes: # type: ignore |
| 937 | shapes_with_positions.extend(collect_shapes_with_absolute_positions(shape)) |
| 938 | |
| 939 | if not shapes_with_positions: |
| 940 | continue |
| 941 | |
| 942 | # Convert to ShapeData with absolute positions and slide reference |
| 943 | shape_data_list = [ |
| 944 | ShapeData( |
| 945 | swp.shape, |
| 946 | swp.absolute_left, |
| 947 | swp.absolute_top, |
| 948 | slide, |
| 949 | ) |
| 950 | for swp in shapes_with_positions |
| 951 | ] |
| 952 | |
| 953 | # Sort by visual position and assign stable IDs in one step |
| 954 | sorted_shapes = sort_shapes_by_position(shape_data_list) |
| 955 | for idx, shape_data in enumerate(sorted_shapes): |
| 956 | shape_data.shape_id = f"shape-{idx}" |
| 957 | |
| 958 | # Detect overlaps using the stable shape IDs |
| 959 | if len(sorted_shapes) > 1: |
| 960 | detect_overlaps(sorted_shapes) |
| 961 | |
| 962 | # Filter for issues only if requested (after overlap detection) |
| 963 | if issues_only: |
| 964 | sorted_shapes = [sd for sd in sorted_shapes if sd.has_any_issues] |
| 965 | |
| 966 | if not sorted_shapes: |
| 967 | continue |
| 968 | |
| 969 | # Create slide inventory using the stable shape IDs |
| 970 | inventory[f"slide-{slide_idx}"] = { |
| 971 | shape_data.shape_id: shape_data for shape_data in sorted_shapes |
no test coverage detected