Turn figures into editable objects instead of putting screenshots into slides. Deliver in Chinese by default, and clearly state which objects are editable and which effects are still images.
First determine the goal
- PDF only: SVG → Chrome print. Verify real text, vector paths, and page dimensions; do not additionally generate a PPTX.
- Editable PPTX needed, and SVG is available: Prefer recovering native geometry from SVG and importing text from PDF; do not deliver only full-page images.
- PDF only: You may try importing text and graphics with LibreOffice, but gradients/clipping may be damaged. Without SVG, this skill's geometry reconstruction script cannot be used; check the result first, then decide whether to ask the user to provide the source SVG.
- Appearance only, no per-element editing needed: You may embed SVG + PNG fallback, but you must state that this is not a native object version. PowerPoint's "Convert to Shape" can serve as an alternative, with no promise that all versions support it.
Look for the original PPTX first; if an existing source file can meet the requirements, do not perform a lossy round trip.
Installation (one-time, on any machine)
Script paths are resolved to absolute paths relative to the directory containing this SKILL.md , not relative to the project cwd. Replace the directory in the example below with the actual directory containing the SKILL.md you loaded (common:~/.agents/skills/ or ~/.pi/agent/skills/; symlinks will be resolved by readlink -f ).
SKILL_DIR="$(dirname "$(readlink -f ~/.agents/skills/editable-vector-slides/SKILL.md)")"
bash "$SKILL_DIR/scripts/install.sh"
install.sh does three things, idempotent and rerunnable:
pip install python-pptx Pillow fonttools lxml(on failure, fall back in order to--user、--break-system-packages; if it still fails, prompt the user to create a venv and rerun withPYTHON=<venv python>).- Check system tools and print installation hints for each distribution: one of Chrome/Chromium,
mutool(mupdf-tools)、pdfimages/pdftoppm(poppler-utils)、LibreOffice。It only checks and does not install system packages—it does not reinstall LibreOffice/Inkscape and does not modify global environment variables. - Run the
check.pysmoke test.
Output SETUP OK is required to perform conversion; PDF-only mode requires only Chrome + mutool. If fonts are missing (especially Times New Roman), install the fonts first:fc-match You need to see the actual matched font names; do not judge based only on the command succeeding.
Execute
SKILL_DIR="$(dirname "$(readlink -f ~/.agents/skills/editable-vector-slides/SKILL.md)")"
# PDF + 原生可编辑 PPTX(默认)。输出目录必须不存在,防止覆盖用户文件;源 SVG 不动。
python3 "$SKILL_DIR/scripts/convert.py" /absolute/input.svg \
--format both --output-dir /absolute/new-output-dir
# 只生成 PDF;不需要 python-pptx/LibreOffice/Poppler。
python3 "$SKILL_DIR/scripts/convert.py" /absolute/input.svg \
--format pdf --output-dir /absolute/new-pdf-dir
If Chrome's sandbox is unavailable in the local isolated environment, explicitly add --no-sandboxonly for trusted input; do not disable the sandbox by default. Input still needs to go through trust assessment first; the script rejects DTDs, scripts, event attributes, and external resources, but this is not a secure sandbox for arbitrary untrusted SVG.
By default both;pptx also retains the intermediate PDF as a reference. The script allows a maximum of 180 seconds per external command, runs everything in the foreground, and does not start a persistent UNO listener; on timeout/interruption, it only terminates the independent process group of the current command, and does not match or kill the user's other sessions.
Artifacts
new-output-dir/
├── input.pdf
├── input.pptx # 仅 PPTX/both 模式
├── reference.png # 原 PDF 渲染
├── preview.png # PPTX → LibreOffice → PDF → PNG
├── report.json # 尺寸、对象数、检查结果、限制
└── work/ # 临时 XML、文字模板、提取图片、commands.log
Deliver the file or copy it to the user-specified location only after verification is complete. On failure, retain work/commands.log for diagnosis; do not call a file that opens as a ZIP but has zero pages/blank pages a success.
Input scope of the native PPTX auxiliary script
This is a bounded conversion solution, not a general-purpose SVG engine. When preflight fails, read the error first; do not delete unrecognized nodes to "make it pass". When extension is needed, make the minimal adaptation according to the file's actual structure and verify again.
Supported:
- Self-contained single-page SVG, with explicit width/height and a viewBox starting from
0 0; the physical dimensions are proportional to the viewBox. - Already expanded
<path>: M/L/H/V/C/S/Z (including relative commands), single contour; Bezier curves are preserved as native DrawingML curves. - Nested groups, fills, strokes, line caps/joins;
data-namecan be preserved as object names. - Real
<text>/<tspan>: using Chrome PDF and LibreOffice text import; complex fonts are not re-laid-out by ourselves. - Directly defined
userSpaceOnUselinear gradients; numeric stops from 0 to 1. Gradient angles and color stops are preserved. - Full-page background rect.
- Single-path Gaussian-blur shadows each in their own group: extract the PDF image + SMask, and composite the correct transparency. Match by drawing order, verify count, size, filter bounds, and opacity; do not hard-code PDF object numbers.
Not supported or requires manual handling:
- Geometric transforms, use/symbol, non-background rect/circle/ellipse, holes in compound paths, mask/clipPath, CSS style sheets, radial gradients, other filters, embedded images. First expand/convert to paths in the source editor, or extend the script for the actual need.
- All text is placed above the geometry. Designs where text should be occluded by other graphics must have z-order rebuilt separately; this approach is not suitable for direct use.
- Gradient start/end point offsets are not precisely remapped, angles/color stops are preserved but the distribution may change slightly. If the visual result is unacceptable, then implement endpoint projection; do not claim pixel exactness.
- Font subsets and PDF import may split words and super/subscripts into multiple text boxes; LibreOffice round-trips may slightly shift text baselines (observed in small-image regression samples). When pixel-level alignment is needed, adjust text positions based on the preview; do not assume imported coordinates are perfectly accurate. Editable does not mean the original PowerPoint paragraph structure has been restored.
- The original groups, layers, animations, masters, or the original author's parametric shape semantics are not restored; shapes can have fill/stroke/nodes modified.
The script will reject known unsupported structures, but all conversions still require visual acceptance.
How it works (read before modifying the script)
-
SVG → PDF
width/heightparses units: unitless/px at 96 DPI;in/cm/mm/pt/pcconverted to inches.- Temporary HTML:
@page { size: Win Hin; margin:0 },imgsame dimensions. - Chrome headless printing, no header or footer. Uses a separate profile so existing browser sessions are unaffected.
mutool draw -F tracevalidates one page, MediaBox, text, and images.
-
PDF → text template
- LibreOffice: PDF → ODG; read the actual node types inside the ZIP, rather than inferring "already editable" from file size.
- In the ODG ZIP, change the mimetype/manifest graphics type to presentation; change content.xml's
office:drawingtooffice:presentation, and save as ODP. - ODP →
pptx:Impress MS PowerPoint 2007 XML; keep its text frames, discard the imported graphics. scripts/convert.py'sodg_to_odp()can be reused independently; still verify page count and text.
-
SVG geometry → DrawingML
fontToolsparses curves and bounds; converts to EMU based on the page/viewBox ratio.- Standard conversion: 1 inch = 914400 EMU; 1 pt = 12700 EMU. It is only true when viewBox is exactly 1/100mm,
360 EMU/SVG unit, and this constant cannot be used for other SVGs. - Each path generates
a:custGeom; remove automatic theme styles to avoid overriding the source fill/stroke. - Native
a:gradFillreplaces the gradient bands split out by LibreOffice. - Restore shadow position, RGB, SMask, and group opacity from the PDF.Do not assume the SMask object number is RGB + 1, and do not omit multiplying by the group opacity.
- Add the text back and correct the
TimesNewRoman→Times New Romannames encountered in this approach; renumber allcNvPr id。
-
Verify and deliver
- See the next section; being able to read the ZIP is not proof of correct rendering.
Acceptance checklist
The automated script has checked:
- Single page, SVG/PDF/slide sizes match, and the PPTX ZIP can be read normally.
- Native path count, shadow count, text box count; output
report.json, without hardcoding 1540/139/9. - Thewhitespace-stripped character multisetof the source text and the PPTX text are equal. This only checks for lost/added characters, and does not prove that the order, layout, or semantics are correct.
- Shadow count, pixel dimensions, resource/draw order, position, and opacity are consistent.
- The PPTX can be re-rendered through LibreOffice.
The Agent must also do:
- Use
readto viewreference.pngandpreview.png; check text line breaks/subscripts and superscripts, arrow endpoints, rounded corners, shadows, gradient stripes, and module occlusion. - Check the object composition: there must be text boxes and vector paths, not just a full-page image; count the actual raster content.
- Clearly state the remaining deviations for complex fonts/occlusion/gradients; if the image cannot be viewed, say outright that only structural verification was completed.
- When it has not yet been opened in Microsoft PowerPoint, do not claim that Office real-machine compatibility testing has been done. It is recommended to open and check it in PowerPoint with the same font names.
- Keep the delivery brief: clear paths, editable content, the parts retained as images, and the actual verification scope.
Pitfalls already encountered
- On some machines, LibreOffice lacks
libreglo.so: the subprocess needs to be givenLD_LIBRARY_PATH=<program dir>; the script automatically detects it from the soffice location and common installation directories (/usr/lib*/libreoffice/program, /opt, /snap), and only reports an error if detection fails. If UNO really must be used, use the system python3, not conda Python. - Exporting PPTX directly from Draw once generated zero pages small files. Forcing the Impress filter or only changing the extension cannot prove success.
- SVG → ODG is often just a graphic frame + SVG/preview image, and does not mean it was split into native objects.
- Importing PDF graphics splits gradients into bands, loses clipping, and produces white seams/blocks. Treat it as a text template, not as the final high-fidelity graphic source.
- In UNO,
while source.getCount(): target.add(source.getByIndex(0))does not guarantee that the source count decreases, and may copy indefinitely. This approach completely bypasses cross-document shape transport. - Do not use
pkill -fto match a string contained in the current command line, as it will kill the executing shell; this approach does not do global process killing. - SVG Gaussian blur became a raster shadow in this Chrome PDF; do not expand this into claims that “all renderers necessarily rasterize” or “no image quality loss”.
Minimal regression check
python3 "$SKILL_DIR/scripts/check.py"
# 对实际输入完成端到端转换后,仍要按验收清单看图。
Used SPAR_Editable_Pipeline.svg verified reference scale: 18×9 inch, 1,540 native paths, 139 text boxes, 83 gradient fills, 9 transparent shadows; these are the acceptance results of the example, not script input limits.