powerpoint

Create, read, edit .pptx decks with python-pptx.

  • pptx
  • powerpoint
  • presentations
  • slides
  • office
  • python-pptx

Declared platforms: linux · macos · windows

Install
npx skills add 'https://github.com/NousResearch/hermes-agent/tree/main/skills/productivity/powerpoint'
Download bundle ↓
main · 24fd22bScanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md
#!/usr/bin/env python3"""Render every slide of a .pptx to per-slide PNG images. Pipeline: LibreOffice (soffice --headless --convert-to pdf) turns the deckinto a PDF, then poppler (pdftoppm, or pdftocairo as an alternate) splitsthe PDF into one PNG per slide. Output is JSON. When both tools are present:  {"rendered": true, "files": ["render/slide-1.png", ...]}When either tool is missing the script still exits 0 and reports:  {"rendered": false, "missing": ["soffice"], "guidance": "..."}so callers can degrade gracefully (fall back to pptx_read.py --outline)."""import argparseimport globimport jsonimport osimport shutilimport subprocessimport sysimport tempfile  def find_tools():    """Return (soffice, splitter, missing) using shutil.which."""    soffice = shutil.which("soffice")    splitter = shutil.which("pdftoppm") or shutil.which("pdftocairo")    missing = []    if not soffice:        missing.append("soffice")    if not splitter:        missing.append("pdftoppm (or pdftocairo)")    return soffice, splitter, missing  def render(pptx_path, out_dir, prefix, dpi):    soffice, splitter, missing = find_tools()    if missing:        return {            "rendered": False, "missing": missing,            "guidance": "Install LibreOffice (soffice) and poppler-utils "                        "(pdftoppm/pdftocairo) to render slides. Without "                        "them, verify decks with pptx_read.py --outline "                        "instead.",        }     os.makedirs(out_dir, exist_ok=True)    with tempfile.TemporaryDirectory() as tmp:        proc = subprocess.run(            [soffice, "--headless", "--convert-to", "pdf",             "--outdir", tmp, pptx_path],            capture_output=True, text=True, encoding="utf-8",            errors="replace", timeout=300)        pdfs = glob.glob(os.path.join(tmp, "*.pdf"))        if proc.returncode != 0 or not pdfs:            raise SystemExit(f"soffice PDF conversion failed: {proc.stderr}")        pdf = pdfs[0]        out_prefix = os.path.join(out_dir, prefix)        proc = subprocess.run(            [splitter, "-png", "-r", str(dpi), pdf, out_prefix],            capture_output=True, text=True, encoding="utf-8",            errors="replace", timeout=300)        if proc.returncode != 0:            raise SystemExit(f"{os.path.basename(splitter)} failed: "                             f"{proc.stderr}")     files = sorted(glob.glob(out_prefix + "*.png"))    return {"rendered": True, "files": files}  def main(argv=None):    if hasattr(sys.stdout, "reconfigure"):        sys.stdout.reconfigure(encoding="utf-8", errors="replace")    parser = argparse.ArgumentParser(        description="Render each slide of a .pptx to a PNG via "                    "soffice + pdftoppm/pdftocairo.",        epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)    parser.add_argument("pptx", help="path to the .pptx file")    parser.add_argument("--outdir", default="render",                        help="directory for PNGs (default: ./render)")    parser.add_argument("--prefix", default="slide",                        help="PNG filename prefix (default: slide)")    parser.add_argument("--dpi", type=int, default=100,                        help="render resolution (default: 100)")    args = parser.parse_args(argv)     result = render(args.pptx, args.outdir, args.prefix, args.dpi)    print(json.dumps(result, indent=2))    return 0  if __name__ == "__main__":    sys.exit(main()) 
Referenced from SKILL.md