---
name: pptx
description: Create, read, and edit PowerPoint presentations via python-pptx
metadata:
  activation:
    keywords: [presentation, powerpoint, pptx, slides, slide deck, .pptx]
    patterns:
      - "(?i)\\b(create|write|edit|read|open|build|make)\\b.{0,30}\\b(presentation|powerpoint|pptx|slides|deck)\\b"
      - "(?i)\\b(pitch|keynote|slide)\\s+(deck|show|presentation)\\b"
      - "(?i)\\.pptx\\b"
  requires:
    tools: [shell]
    packages: [pptx]  # dist: python-pptx, imports as `pptx`
---

# PowerPoint Presentation (.pptx) Workflows

## Quick Reference

| Task | Tool | Install |
|------|------|---------|
| Read/extract text | `markitdown` or `python-pptx` | `pip install "markitdown[pptx]"` |
| Create new presentation | `python-pptx` | `pip install python-pptx` |
| Edit existing | `python-pptx` | `pip install python-pptx` |
| Convert to PDF/images | LibreOffice + Poppler | System packages |
| Visual QA | Convert to images → inspect | See below |

## Reading Content

```bash
# Extract text with markitdown
python -m markitdown presentation.pptx

# Or with python-pptx
python -c "
from pptx import Presentation
prs = Presentation('presentation.pptx')
for i, slide in enumerate(prs.slides, 1):
    print(f'--- Slide {i} ---')
    for shape in slide.shapes:
        if shape.has_text_frame:
            print(shape.text)
"
```

## Creating Presentations

```python
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor

prs = Presentation()
prs.slide_width = Inches(13.333)   # Widescreen 16:9
prs.slide_height = Inches(7.5)

# --- Title Slide ---
slide_layout = prs.slide_layouts[0]  # Title layout
slide = prs.slides.add_slide(slide_layout)
slide.shapes.title.text = "Presentation Title"
slide.placeholders[1].text = "Subtitle text"

# --- Content Slide with custom elements ---
blank_layout = prs.slide_layouts[6]  # Blank layout
slide = prs.slides.add_slide(blank_layout)

# Background color
from pptx.oxml.ns import qn
bg = slide.background
fill = bg.fill
fill.solid()
fill.fore_color.rgb = RGBColor(0x1E, 0x27, 0x61)  # Dark navy

# Title text box
txBox = slide.shapes.add_textbox(Inches(0.8), Inches(0.5), Inches(11), Inches(1))
tf = txBox.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.text = "Slide Title"
p.font.size = Pt(36)
p.font.bold = True
p.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)

# Content text box
txBox = slide.shapes.add_textbox(Inches(0.8), Inches(1.8), Inches(5.5), Inches(5))
tf = txBox.text_frame
tf.word_wrap = True
for item in ['First point', 'Second point', 'Third point']:
    p = tf.add_paragraph()
    p.text = item
    p.font.size = Pt(16)
    p.font.color.rgb = RGBColor(0xCA, 0xDC, 0xFC)
    p.space_after = Pt(12)

# Image
slide.shapes.add_picture('chart.png', Inches(7), Inches(1.8), width=Inches(5.5))

# Speaker notes
notes_slide = slide.notes_slide
notes_slide.notes_text_frame.text = "Talking points for this slide..."

prs.save('output.pptx')
```

### Key patterns

- **Slide sizes**: Widescreen `13.333×7.5"`, Standard `10×7.5"`
- **Layouts**: Inspect `prs.slide_layouts[i].name` — indices vary by template
- **Units**: Always use `Inches()` or `Pt()` — raw EMU values are error-prone
- **Text frames**: Set `word_wrap = True` to avoid overflow
- **Margins**: Keep `≥0.5"` from slide edges

### Shapes and elements

```python
# Rectangle shape
from pptx.enum.shapes import MSO_SHAPE
shape = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
    Inches(1), Inches(2), Inches(4), Inches(2))
shape.fill.solid()
shape.fill.fore_color.rgb = RGBColor(0x02, 0x80, 0x90)
shape.line.fill.background()  # No border

# Table
table = slide.shapes.add_table(rows=3, cols=4,
    left=Inches(0.8), top=Inches(2), width=Inches(11), height=Inches(3)).table
table.cell(0, 0).text = "Header"

# Chart (basic)
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE
chart_data = CategoryChartData()
chart_data.categories = ['Q1', 'Q2', 'Q3', 'Q4']
chart_data.add_series('Revenue', (150, 180, 210, 240))
slide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED,
    Inches(1), Inches(2), Inches(10), Inches(5), chart_data)
```

## Editing Existing Presentations

```python
from pptx import Presentation

prs = Presentation('existing.pptx')

# Edit specific slide
slide = prs.slides[0]  # 0-indexed
for shape in slide.shapes:
    if shape.has_text_frame:
        if 'OLD_TEXT' in shape.text:
            for paragraph in shape.text_frame.paragraphs:
                for run in paragraph.runs:
                    run.text = run.text.replace('OLD_TEXT', 'NEW_TEXT')

# Add a slide at the end
layout = prs.slide_layouts[1]
new_slide = prs.slides.add_slide(layout)
new_slide.shapes.title.text = "New Slide"

# Delete a slide (by index) — uses private API; may break across python-pptx versions
rId = prs.slides._sldIdLst[2].rId
prs.part.drop_rel(rId)
del prs.slides._sldIdLst[2]

prs.save('modified.pptx')
```

**Limitations of python-pptx**: Limited support for animations, transitions, embedded media, and some chart types. For complex edits, consider XML-level manipulation (similar to docx approach).

## Converting to Images (for QA)

Requires LibreOffice + Poppler (`pdftoppm`). On Windows: `choco install poppler` or download Poppler binaries and add to PATH.

```bash
# Convert to PDF first
libreoffice --headless --convert-to pdf output.pptx

# Then to individual slide images
pdftoppm -jpeg -r 150 output.pdf slide
# Creates slide-01.jpg, slide-02.jpg, etc.
```

## Design Guidelines

When creating presentations, aim for visual impact:

- **Choose a color palette** — pick 3-4 colors that match the topic. Don't default to generic blue
- **Dark/light contrast** — dark backgrounds for title + conclusion, light for content
- **One visual per slide** — every slide should have an image, chart, icon, or shape
- **Font sizing**: Title 36-44pt, body 14-16pt, captions 10-12pt
- **Vary layouts** — don't repeat the same slide structure; alternate columns, grids, callouts
- **Left-align body text** — center only titles
- **Minimum margins**: 0.5" from slide edges
- **Avoid text-only slides** — add visual elements to maintain engagement

## Visual QA Process

Always verify generated presentations:

1. Convert to images (see above)
2. Inspect each slide for:
   - Overlapping text or elements
   - Text cut off at boundaries
   - Uneven spacing or alignment
   - Low contrast (light text on light background)
   - Missing content or leftover placeholders
3. Fix issues and re-verify
4. Don't skip QA — the first render is rarely correct

## Best Practices

- **Always set slide dimensions explicitly** — template defaults vary
- **Use `word_wrap = True`** on all text frames
- **Test with real content** — placeholder text may fit but real content may overflow
- **Preserve template layouts** — when editing, match existing styles and conventions
- **Back up originals** — save to a new filename when editing
- **Speaker notes** — include talking points for each slide
