Process one at a timeFor each image, forcibly split it into four layers and then composite an editable .pptx (from bottom to top). The first three image layers must be generated or extracted by imagegen, and the text layer is extracted by GPT vision capabilities and written as real text boxes:
背景图(复刻) + 整体框架图(绿幕抠图,默认不切分) + 元素图标/装饰(绿幕抠图,切片) + 文字(GPT视觉提取)
🟣 Direct conversion principle: when the user provides an image and requests conversion to an editable PPTX,do not first scan the current directory, historical outputs, or other projects to find/reuse similar source pages. Directly use the current image provided by the user as the only source image, extract the background image, framework image, element icons, and text according to the B1-B9 process, and create a new PPTX document. Only when the user explicitly requests reusing old assets, continuing a historical output, or specifying an existing source file should the corresponding historical file be read.
🧱 Task isolation principle (prevent file mixing): before each conversion starts, a unique task root directory must be created
RUN_ROOT, for exampleimage2pptx_runs/<时间戳>_<源图slug>/, and all intermediate products, prompts, manifests, layouts, previews, QA, and the final PPTX for this task must be written under that directory. It is forbidden to write a new task directly to the workspace's fixededitable/01、out/、qa/orslide-01/, and it is also forbidden to read assets from these fixed paths. If the directory already exists, a new directory must be used; it must not be reused or overwritten.
layout.jsonThe image paths forRUN_ROOT: single-page layout takes priorityomitassets_dir(letcompose_pptx.pyautomatically use the directory where the layout is located), or write it as an absolute page directory; do not write relative paths such as"assets_dir": "editable/01"that are affected by the current working directory. The manifest'scopied_tomust also be an absolute path withinRUN_ROOT.
🟦 Framework image = all images on a page other than "background, element icons/decorations/artistic text, and ordinary text": containers/cards (including background fills and title bars), separator/connector lines,all chart graphics (line/bar/stepped/pie charts/coordinate grids/trend lines), ribbons, decorative lines, and color blocks—all are classified as framework images, extracted in one pass, andshape, size, and position must match the original image 1:1(do not miss data polylines/decorations).
🟨 Artistic text = decorative elements, not ordinary text: any text with gradient colors, calligraphic/brush styling, deformation, stroke/shadow/texture, badge-style typography, or that cannot be directly written with ordinary fonts is classified into the B4 icon/decoration layer and extracted and placed as image elements. For example, the large cover text "Lingzhi". The B7 GPT visual text layer only handles text that can be directly restored with ordinary fonts.
🔴 The four layers are mandatory and none may be omitted (core iron rule):Background image → overall framework image → element icons → text. These four steps are the essence of this skill.Any page must genuinely produce a "framework image (B3)" and an "element icon image (B4)" and perform green-screen keying, using the full transparent
frame.pngComposite as the framework visual layer; only when the user explicitly requests "movable framework parts / split the framework / split it into pieces" should the framework image be cut along transparent regions intoframe_parts/then composited. Prohibited degraded practices: ① directly using the original image as the background and overlaying text (double text); ② using native PPTshapes/ color blocks / lines to redraw the background, cards, title bars, charts, timelines, decorations; ③ cropping a portion of the original image to use as background, framework, or icon material; ④ omitting the framework/icons; ⑤ using code/PIL/SVG/HTML/Canvas to draw the image layer. The background image, framework image, and element icon image must all come from imagegen extraction-style generation: for the background, use imagegen to reproduce a clean background; for the framework image, use the fixed B3 prompt to generate a full-frame layer on a solid-color cutout base; for icons/decorations, use imagegen to generate an icon sheet on a solid-color cutout base, and do not draw grid divider lines in the icon sheet.chroma_key.pyis only responsible for background removal,slice_grid.pyis only allowed to split icon sheets generated by imagegen and already background-removed; only if the user explicitly requests framework splitting is it allowed to split the already background-removedframe.png. It must not split the original slide screenshot. Hard gate for generation evidence: B2/B3/B4 must record real imagegen call evidence inimagegen-assets-manifest.json:backendmust be an imagegen-type backend,generated_sourcemust point to or describe a real generated result,prompt_filemust point to the prompt file used on this page, andcopied_tomust be the corresponding image within the delivery directory. If the manifest showsprogrammatic、local layer generator、PIL、SVG、HTML、Canvas、matplotlib、screenshot renderer、null prompt_fileor other signs of non-imagegen generation, the conversion of this page fails and must be redone; it cannot be delivered.
Hard gate for image layer generation
In this skill, "image → editable PPTX" is not redrawing the page with PPT color blocks. The editable boundary is:
- Text: written as editable text boxes.
- Background/framework/icons/decorations/chart graphics: generated by imagegen as the image layer; by default the framework image is placed into the PPT as a whole transparent
frame.png(movable as a whole, replaceable, scalable), and icons placed into the PPT can be moved, replaced, and scaled. Only when the user explicitly requests framework splitting should the background-removed framework image be cut along transparent regions into movable framework parts.
The following methods are prohibited as substitutes for the image layer:
- Redrawing the background/cards/framework/icons/decorations/charts in PPTX using native shapes, filled color blocks, lines, arrows, tables, or chart components.
- Cropping a portion of the original slide screenshot as background, framework, vehicle, icon, or decoration material.
- Using Python/PIL, SVG, HTML, Canvas, matplotlib, or screenshot rendering to generate background/framework/icon images.
- First building the page with native PPT elements, then exporting it as the image layer.
What code is allowed to do is limited to:
probe_palette.pycolor probing.- Copying the image generated by imagegen to this
RUN_ROOT/editable/NN/。 chroma_key.pybackground-removing the framework image/icon image generated by imagegen.slice_grid.py --auto/--gridsplitting the icon sheet generated by imagegen.- Optional: only when the user explicitly requests framework splitting, use
slice_grid.py --componentsto split along transparent regions theframe.pnggenerated by imagegen and already background-removed, then useframe_parts_to_icons.pyto generateicons[] role:"frame_part"。 - write
layout.json/deck.json, and composite the PPTX and preview. layout_guard.pyvalidate or correct the coordinate contract oflayout.json:ref_width/ref_heightMust match the actual pixel dimensions of the source image,source_bboxandx/y/w/hmust be consistent.visual_compare_qa.pyAfter unifying the dimensions of the source image and the final PPTX preview, generate a side-by-side image, an overlay image, a difference heatmap, and diagnostic metrics, so that GPT vision can judge whether the text/icons align with the original PPT image.- Optionally crop/scalethe entire imagegen-generated imageat a uniform ratio; do not crop a local region of the original image and pass it off as an asset.
Each page must include imagegen-assets-manifest.json, recording the generated_source、copied_to、layer、prompt_file、backend、key_colorof B2/B3/B4. If there is no manifest, or any image layer is missing generated_source / prompt_file, or any image layer's backend is not imagegen, the conversion of this page has failed and it cannot be delivered.
For the complete pipeline, prompts, coordinate/font-size conversion, and the QA feedback loop, see references/image-to-pptx.md; for runtime and image backend, see references/runtime-notes.md。
Runtime and image backend (read first)
- Image generation (replicating backgrounds, framework diagrams, icon images) must use a raster image generation backend: for Codex use the built-in
imagegen/ imagegen(supports using the original image as input for "extractive" image generation); other runtimes use their native image generation tools.Prohibited : SVG/HTML/Canvas/code drawing, PPT shapes, cropping a local region of the original image and passing it off as an asset. - For transparent cutout use this skill's built-in
scripts/chroma_key.py(preserve color and lines/preserve shape)—internally opaque pixel colors are 100% preserved (red/navy/gray/white never fade), and by default edges are not eroded (thin lines/glow are not lost);frame-safe/icon-safeenhances the alpha of semi-transparent edges and only uses binary gap repair to fix breakpoints in thin lines, avoiding misaligned horizontal/vertical lines and incomplete arcs. For frameworks/icons, by default add--scale 2first supersample the cutout, then scale it back to the target size in PPT, making horizontal/vertical lines and arcs smoother.Do not use aggressive--soft-matte --despill --edge-contractcombinationsto cut out flat images (it will discolor and lose lines). - Reading images (text/icon localization) must use GPT's own vision capabilities and output structured JSON. Do not first run traditional OCR engines such as tesseract, EasyOCR, or system OCR.
imagegen image passing / edit target hard gate
When Codex's built-in image_gen generates B2/B3/B4,you must first use view_image to open the current page's source image, making this image the visible edit targetin the current conversation, and then call image_gen. The prompt must explicitly state "use the image just shown as the sole edit target, and extract or erase on its basis to generate the target layer".Do not treat the source image merely as a style reference, and it is even more prohibited to only write a local file path in the prompt to pass off as passing an image: path text does not automatically pass the image to imagegen, the model will guess from the description, and framework diagrams and icon images will go off track.
Multi-page tasks must be processed page by page: before generating page 1's B2/B3/B4, show only page 1's source image; before generating page 2, re- view_image page 2's source image, and in the prompt point out "the image just shown is this edit's target". If the imagegen output cannot prove it was extracted based on the current edit target, or is clearly inconsistent with the source image, this page's B2/B3/B4 are judged failed and must be regenerated, and cannot proceed to B5-B9.
Per-page workflow (check off item by item)
- [ ] B0 隔离目录:为本次任务创建唯一 `RUN_ROOT`,所有文件只写入/读取该目录;不得复用工作区固定 `editable/01`、`out/`、`qa/`
- [ ] B0a 传图:每页 B2/B3/B4 调 imagegen 前,必须先 `view_image` 当前页源图;prompt 写“以刚刚显示的这张图片作为唯一编辑目标 / edit target,在它的基础上提取或擦除生成目标层”;不得只写本地路径、不得只作为风格参考或凭文字描述猜图
- [ ] B1 探色:probe_palette.py 判断该页是否含绿 → 定本页抠图底色(默认 #00ff00;含绿改 #ff00ff 等)
- [ ] B2 背景:用 imagegen 复刻干净背景(无任何文字/图标/框架/卡片/占位块),禁止用 PPT 色块、程序绘图或裁原图;写 prompt 文件并登记真实 imagegen 调用记录
- [ ] B3 框架图:用 imagegen 在抠图底色上提取框架图,生成图片提示词固定为“生成一张图片,提取这张图片中的框架图,纯色背景,背景色值为XXXXXX,「框架图」= 原图里**除背景/图标/装饰/艺术字/普通文本外的一切**(容器轮廓与**底色填充/标题条/辉光**、分隔/连接线、**全部图表图形:折线/柱状/阶梯/饼图/坐标网格/趋势线**、缎带/装饰)→ 形状·大小·位置与原图 **1:1 一致**,保留原色与填充,别漏数据折线/装饰、别自己额外加空心线框、占位框;不要出现文字、不要出现图标;”;只允许把 XXXXXX 替换为 B1 决定的背景色值(默认 #00ff00;原图有绿色则改 #ff00ff、#8000ff 等原图没有的颜色);写 prompt 文件并登记真实 imagegen 调用记录
- [ ] B4 图标图:先用 GPT 视觉对比**原图 vs B3 frame 预览**,列出「源图全部图标/装饰/艺术字清单」和「已误入 frame 的图标清单」;B4 prompt 只生成 frame 里没有的元素,避免同一图标在 frame 与 icons 双重出现;用 imagegen 把缺失元素排成 N×N 等分方格网(小图标 4×4,大装饰/物品图/艺术字 2×2 或单独大格),多了出多张;方格网不要画分割线,不画实线和虚线,提示词里要明确写出这一点;如果最终生成的图片不小心有了方格分割线也没关系,先抠图,然后裁剪掉分割线就好(因为每个网格有留白);禁止从原图裁图标、程序绘制图标或艺术字;写 prompt 文件并登记真实 imagegen 调用记录
- [ ] B5 抠图与图标切分:scripts/chroma_key.py 给 imagegen 生成的框架图+图标图去底(框架用 `--preset frame-safe`,图标/艺术字用 `--preset icon-safe` 保边)→ 默认保留整张透明 `frame.png`,不做框架切分;图标表用 `slice_grid.py --auto --pad 24 --contact-sheet` 按透明空隙切成单个透明图标 → 查看 `icons_contact_sheet.png`、`frame.png` 灰底自检;任一图标被切断、粘连、缺边、edge_touch 异常,必须重出或重切,不能交付。若用户明确要求框架切分,再运行 `slice_grid.py --components --pad 0 --contact-sheet --prefix fp` 把 `frame.png` 切成 `frame_parts/`
- [ ] B6 定位:默认最终 `layout.json` 使用整张 `frame.png` 作为框架视觉层:写 `"frame":"frame.png"`,不要把框架切成 `frame_parts`。再逐个量出每个普通图标/艺术字在**源图实际像素坐标系**里的 `x/y/w/h` bbox,并换算成比例写入:`x=x_px/ref_width`、`y=y_px/ref_height`、`w=w_px/ref_width`、`h=h_px/ref_height`(manifest 只有素材表尺寸,必须补原图实测坐标;保持宽高比、尺寸贴合原图)→ `layout.json` 默认用 `units:"fraction"`;`view_image`/浏览器/预览图显示的缩略坐标不能直接写入,必须按 `源图宽/显示宽` 与 `源图高/显示高` 分别换回源图像素;禁止只把 x 放大、y 不放大这类混合坐标。首次合成后必须按预览反向校准普通图标尺寸/位置,缩放一律以源图 bbox 中心点为锚点,禁止按切片素材尺寸或视觉感觉直接摆放。若用户明确要求框架切分,才运行 `frame_parts_to_icons.py` 读取 `frame_parts/icons_manifest.json`,按每个框架切片在 `frame.png` 中的 bbox 映射成比例坐标,生成 `icons[] role:"frame_part"` 条目;这个 bbox 回放是拼回原 `frame.png` 布局的保证
- [ ] B7 文字:用 GPT 视觉读取原图所有**普通字体文字**(内容/像素位置/字号/颜色/粗细/对齐) → 先量**源图实际像素 bbox**,再按比例写入 layout:`x/y/w/h` 用 fraction,字号优先用 `size_ratio = 源图实际文字高度像素 / ref_height`(或 `size_pct = size_ratio*100`),如果用户或源 PPT 期望 PowerPoint 号数字号,也可以直接写 `size` 绝对 pt;不要把缩略图上的文字高度当作源图 `size_px`。换算公式是 `pt = size_ratio × (slide_height_in×72) = size_px × (slide_height_in×72) / ref_height`,反推为 `size_px = 目标pt × ref_height / (slide_height_in×72)`。如果坐标来自 2048×1143 这类缩略显示,而源图是 4096×2286,必须先把 `x/y/w/h/source_bbox/size_px` 全部乘以 2 后再写入;例如 7.441in 高、2286px 源图中,20px 只会得到 4.69pt,9pt 应写约 38.4px。艺术字只记录为 B4 图标/装饰定位,不写入普通文本框;首次预览后必须对照源图微调文本框比例、字号比例和行距,确保换行、基线和相对图标位置还原原图。**先定字体粗细/字号/行距,再回校位置**:`bold` 默认 `false`,普通正文不要全加粗,只有各级标题、按钮标题、重点词按原图加粗;多行正文段落优先用约 `line_spacing:1.2`,否则后续改粗细/行距会改变换行和视觉 bbox,让已量好的坐标再次漂移。
- [ ] B7a 坐标与样式契约校验:合成前必须运行 `layout_guard.py 源图 layout.json --strict`。`ref_width/ref_height` 必须等于源图实际像素尺寸;`source_bbox` 必须覆盖源图中真实对象,而不是覆盖 `view_image` 缩略坐标位置。若量测来自同宽高比缩略图,先把 bbox 与 `size_px` 缩放回源图像素,或用 `--fix-ref-to-source --fix-fractions --in-place` 归一化,再重新人工复查关键文本和图标。`layout_guard --strict` 还会拦截疑似半分辨率字号(默认低于 6pt、或 `source_bbox` 行高明显大于 `size_px`)和“正文全加粗”(6 个以上文本框超过 85% bold);真实小字必须显式写 `small_text_ok:true`,真实全粗体页必须写 `allow_all_bold_text:true` 并在 QA 备注说明。`layout_guard` 不用页面覆盖高度判错;任何 `source_bbox` 与 `x/y/w/h` 不一致、字号/粗细警告未处理,都不能进入 B8。
- [ ] B7b 源图 bbox 视觉复核:合成前先运行 `placement_qa.py` 只画源图框并打开 `slide_01_source_boxes.png`,确认每个文本/图标框真实圈住源图对象。`layout_guard` 只能发现坐标字段不一致,不能发现“bbox 一致但量错对象/量到错误行”的问题;发现错框必须先改 `source_bbox`,再让 `x/y/w/h` 由 bbox 换算。
- [ ] B7c 框架锚点回校:B7a/B7b 通过后,必须再看**最终合成预览中的 `frame.png`**,对贴在框架上的文本做二次校准:分区标题条、面板标题、按钮文字、底部总结条、页脚/横幅、步骤标签等,不只按源图 bbox 放置,还要按生成后的 `frame.png` 标题条/按钮/底栏的视觉中心线或内边距回校。若 `frame.png` 相对源图有轻微漂移,文本应跟随最终 frame 锚点移动;`layout_guard` 通过不代表这些文本已经视觉对位。记录每个被调整文本的 `frame_anchor`(如 `left_panel_title_bar`、`bottom_summary_bar`)、`dy_px` 和原因到 QA 笔记或 layout 旁文件。
- [ ] B8 合成:compose_pptx.py 生成 .pptx,并 --preview-dir 出预览图
- [ ] B9 QA:检查 `imagegen-assets-manifest.json` 中 B2/B3/B4 是否都有 imagegen 后端、生成源、prompt 文件、交付复制路径,且没有 programmatic/local/PIL/SVG/HTML/Canvas/matplotlib 等违规来源;检查 `frame.png` 叠背景后完整对位、线条/圆弧/填充干净,检查 `icons_contact_sheet.png` 无缺边;运行 `visual_compare_qa.py 源图 最终预览 --out-dir ...`,打开 `side_by_side.png`、`blend.png`、`diff_heatmap.png`,用 GPT 视觉对比源图与最终预览,逐项核对:图标无缺失、无重复叠影、无被切断、位置/大小贴合、文字可读;再用 placement_qa.py 在源图和预览图上画 bbox → 至少执行一轮 `layout.json` 回校(先修图标中心点/尺寸,再修文字框/字号/行距,最后修贴框文本的 frame_anchor 偏移)→ 对比整页预览;图标明显偏小/偏大、压字、离源位置漂移,或文字换行/位置不贴合,都不得交付
Stacking order (bottom to top): background → overall framework diagram (
frame) → element icons (icons) → text (texts). If the user explicitly requests framework segmentation, the order is: background → framework components (icons[]withinrole:"frame_part") → element icons (icons) → text (texts). By default, do not useshapes; unless the user explicitly requests native shape reconstruction,shapesmust not carry any visual content.
Key commands
# B0 本次任务隔离目录(<task-slug> 用源图名或用户任务名的安全短名)
mkdir -p "$PWD/image2pptx_runs"
export RUN_ROOT="$(mktemp -d "$PWD/image2pptx_runs/$(date +%Y%m%d-%H%M%S)_<task-slug>_XXXXXX")"
mkdir -p "$RUN_ROOT/editable/01/icons" "$RUN_ROOT/editable/01/prompts" "$RUN_ROOT/out/preview"
# B1 探色(含绿则推荐改非绿底色)
python3 scripts/probe_palette.py "$RUN_ROOT/editable/01/slide-01.png"
# B5 去底(框架图 + 图标图都去底,保色保线)→ 默认保留整张 frame.png + 图标切片 → 合到灰底自检
python3 scripts/chroma_key.py --input "$RUN_ROOT/editable/01/frame_raw.png" --out "$RUN_ROOT/editable/01/frame.png" --preset frame-safe --scale 2 --force
python3 scripts/chroma_key.py --input "$RUN_ROOT/editable/01/icons_raw_1.png" --out "$RUN_ROOT/editable/01/icons_t_1.png" --preset icon-safe --scale 2 --force
python3 scripts/slice_grid.py "$RUN_ROOT/editable/01/icons_t_1.png" "$RUN_ROOT/editable/01/icons" --auto --pad 24 --contact-sheet --prefix ic
# 非绿底:--auto-key none --key-color "#ff00ff";只有严格等分且元素居中时才用 --grid 4x4
# 可选:仅当用户明确要求框架切分/框架部件可移动时执行
mkdir -p "$RUN_ROOT/editable/01/frame_parts"
python3 scripts/slice_grid.py "$RUN_ROOT/editable/01/frame.png" "$RUN_ROOT/editable/01/frame_parts" --components --pad 0 --contact-sheet --prefix fp
python3 scripts/frame_parts_to_icons.py "$RUN_ROOT/editable/01/frame_parts/icons_manifest.json" --ref-width <源图宽px> --ref-height <源图高px> --out "$RUN_ROOT/editable/01/frame_parts/frame_parts_layout_icons.json"
# B8 合成 + 预览 + 摆放 QA
python3 scripts/layout_guard.py "$RUN_ROOT/editable/01/slide-01.png" "$RUN_ROOT/editable/01/layout.json" --strict
python3 scripts/placement_qa.py "$RUN_ROOT/editable/01/slide-01.png" "$RUN_ROOT/editable/01/layout.json" --slide-index 1 --out-dir "$RUN_ROOT/editable/01/qa-source-boxes"
python3 scripts/compose_pptx.py "$RUN_ROOT/editable/01/layout.json" "$RUN_ROOT/out/<task-slug>.pptx" --preview-dir "$RUN_ROOT/out/preview"
python3 scripts/placement_qa.py "$RUN_ROOT/editable/01/slide-01.png" "$RUN_ROOT/editable/01/layout.json" --slide-index 1 --preview "$RUN_ROOT/out/preview/slide_01.png" --out-dir "$RUN_ROOT/editable/01/qa-placement"
python3 scripts/visual_compare_qa.py "$RUN_ROOT/editable/01/slide-01.png" "$RUN_ROOT/out/preview/slide_01.png" --out-dir "$RUN_ROOT/editable/01/qa-visual"
Key points:
- Directory isolation: Each conversion must first create a unique
RUN_ROOT, and allbackground.png、frame_raw.png、frame.png, optionalframe_parts/、icons_raw_*.png、layout.json、imagegen-assets-manifest.json, preview images, and the final PPTX are all underRUN_ROOT; do not read from or write to a fixed same-named directory in the workspace. - imagegen must pass an image and serve as the edit target: Before generating B2/B3/B4 for each page each time, first
view_imagethe current source image, so that the source image becomes a visible edit target available to imagegen; in the prompt, write "use the image just displayed as the sole edit target, and on its basis extract or erase the target layer to be generated." Do not write only/path/to/slide.png; local path text is not passing an image; also do not treat the source image merely as a style reference. - Matting background color: Default is pure green
#00ff00; if the B1 report contains green, change to non-green (e.g., magenta#ff00ff), and the output background color of B3/B4 stays in sync with B5--key-color. - Image layer source:
background.png、frame_raw.png、icons_raw_*.pngmust be an imagegen-generated image; it must not come from PPT color block drawing, code drawing, or local cropping of the original image. - Do not search historical source pages: Unless the user explicitly requests reuse of old files, do not scan the current directory or historical
outputs/to find similar source pages for image conversion; directly process the current image provided by the user. - B3 prompt fixed: The framework image generation prompt is fixed as "Generate an image, extract the framework image from this image, solid color background, background color value XXXXXX, 'framework image' = everything in the original imageexcept background/icons/decorations/artistic text/ordinary text(container outlines andbackground fill/title bar/glow, dividers/connecting lines,all chart graphics: line/bar/step/pie charts/coordinate grids/trend lines, ribbons/decorations) → shape, size, and position 1:1 consistentwith the original image, retain the original colors and fills, do not miss data lines/decorations, do not add extra hollow wireframes or placeholder boxes yourself; do not show text, do not show icons;". Only replace XXXXXX with the background color value selected by B1.
- Framework image fidelity and default whole image: Framework image = everything except background/icons/decorations/artistic text/ordinary text (includingall chart graphics and decorations), together with cardsbackground fill/title bar/glow/gradientextracted together—the matted framework composited onto the background should ≈ the original image with ordinary text, icons, and artistic text removed, and 1:1 consistentwith the original image. Do not miss the short line under the title, the color bar at the top of the card, underlines,data lines/steps/pie charts, axes/grid lines, ribbon decorations.Do not add extra placeholder boxes or wireframes not present in the original image. After background removal, the
frame.pngBy default, place it into the PPT as the overall framework visual layer; only when the user explicitly requests framework splitting should it be cut into transparent connected regionsframe_parts/and placed into the PPT asicons[] role:"frame_part". - Deduplicate before icon generation: after B3, you must look at the preview of
frame.pngoverlaid on the background, and list the icons/decorations that have already appeared in the frame; B4 should only generate elements that are not in the frame. If an element is already in the frame and in the correct position, do not put it intoicons[]again, otherwise overlapping double images will occur. - Preserve edges when slicing icons/artistic text: generating multiple icons in one image is acceptable, but sufficient gaps must be left; for slicing, prefer
slice_grid.py --auto --pad 24 --contact-sheet, and use a fixed grid only when the elements are strictly centered. You must checkicons_contact_sheet.png: if any icon is missing a corner, missing an edge, cut in half, or anyedge_touchin the manifest is true, it indicates that the border may have been cut damaged, and you must regenerate the icon sheet (enlarge cells/leave more whitespace/split into multiple images) or re-slice; do not deliver. - Hard gate for missing icons: the final preview must be visually checked side by side with the source image. Every ordinary icon/decoration/artistic text in the source image must satisfy one of two conditions: it has already correctly appeared in
frame, or it has already been correctly placed inicons[]. Do not deliver after deleting icons from the final layout just because the icon layer is offset, occluded, or difficult to slice. - Hard gate for coordinate contract:
ref_width/ref_heightmust record the actual pixel dimensions of the source image;source_bboxmust also be in the same source image pixel coordinates.view_image, browser screenshots, and PPT preview PNGs are often thumbnails, not the source image coordinate system; if coordinates are measured on a thumbnail, they must be converted back to source image pixels separately according toscale_x=源图宽/缩略图宽、scale_y=源图高/缩略图高, andsize_pxmust be scaled accordingly. It is forbidden to mix 2048px preview coordinates with 4096px source image dimensions, especially forbidden for x to be estimated according to the source image while y still remains at the thumbnail height, which would squeeze all text/icons into the upper half of the PPTX.layout_guard.py --strictis not responsible for judging visual alignment; visual alignment must be checked against the final composite preview and the source image. - Hard gate for source image frame vision:
layout_guardpassing only means the bbox and fraction are mathematically consistent, not that the bbox measured the correct object. Before compositing, you must openqa-source-boxes/slide_01_source_boxes.png, and confirm item by item that the text/icon boxes cover the true positions in the source image; for example, if a text box such as "key action" circles the upper process area instead of the bottom button, it must be remeasured even if the guard passes. - Hard gate for framework anchor recalibration:
source_bboxEven if correct, misalignment may still occur, because B3'sframe.pngis an imagegen-generated layer, and the title bar, buttons, and bottom bar may have slight vertical/horizontal drift relative to the source image. Any text attached to the framework (section titles, button text, bottom bar summary, footer banner, card titles) must be recalibrated in the final preview according to the visual anchors offrame.png: use the center line, inner padding, or in-frame whitespace of the title bar/button/bottom bar as the standard, and if necessary shift it down/up by a few to several dozen source image pixels as a whole, and recordframe_anchoranddx/dy_px. This step is performed afterlayout_guard --strict. - Placement coordinate precision: use proportional coordinates by default. First measure on the source image
x/y/w/hpixel bbox, then write intox/ref_width、y/ref_height、w/ref_width、h/ref_heightaccording tolayout.json, and setunits:"fraction". Keepsource_bbox:[x_px,y_px,w_px,h_px]for QA convenience. - Icon/artistic text size positioning:Measure each one against the original image
x/y/w/hpixel bbox, then convert it to proportions and write it into layout.json(the manifest only has the asset sheet dimensions, not the original image positions; use the aspect ratio to determine h, do not make it square); after placement you must runplacement_qa.py, and check on the source image and preview image whether the bbox is aligned accurately; do not just look at the final PPT preview. - Hard gate for icon preview re-calibration: after the first preview, you must check each icon one by one for "preview visual bbox vs source image visual bbox". If it is too small/too large, adjust by anchoring at the center point:
new_x = cx - new_w/2、new_y = cy - new_h/2; do not only changew/hand cause the icon to drift, and do not place it directly according to the original size of the sliced asset. When the icon overlaps with text, prioritize restoring the relative position from the source image; if the source image has no overlap but the preview overlaps, you must change the icon or text bbox and rerun B8/B9. - Hard gate for final visual alignment: you must open
qa-visual/side_by_side.png、qa-visual/blend.png、qa-visual/diff_heatmap.png, and use GPT vision to judge whether the text and icons in the composed PPTX preview correspond to the original PPT image. Page content may be only in the upper half, lower half, or a local area; the criterion is whether the position/size/relative relationship of the corresponding objects in the source image is consistent, not how much of the page height the elements cover. - Generate evidence: each page must include
imagegen-assets-manifest.json, recording the real imagegen generation source path, backend, and prompt file for the background, framework image, and icon sheet; if missing,prompt_file:null, or if it shows a program-generated source, it is unqualified. - Text extraction: use GPT vision to directly look at the original image, and output paragraph-by-paragraph text and pixel position styles according to the
texts[]JSON schema; it is forbidden to use external OCR output as the final text result. The bbox of a long text box must cover the entire original text block; do not estimate using the visual center point. - Text position re-calibration: the text in the final preview must match the left/center/right boundaries, first-line baseline, line-break rhythm, and spacing to adjacent icons of the text block in the source image. If the editable font width differs from the handwritten font in the source image, prioritize fine-tuning the
w/hratio,size_ratio/size_pct、line_spacingandalign; do not delete icons or shrink them to a size inconsistent with the source image just to avoid misalignment. The text re-calibration order is fixed as: first setbold/ font size /line_spacing, then fix the bbox; otherwise all-bold or line-spacing changes will alter character width, line breaks, and visual height, causing the just-calibrated position to drift again. - Coordinates/font size: layout.json recommends
units:"fraction"; font size recommendssize_ratio = 源图实际文字高度像素 / ref_height, converted topt = size_ratio × (页高in×72)during compose. The old fieldsize_px/sizeis still compatible, butsize_pxmust be the actual pixels of the source image, not a 2048px preview measurement value; if you need a normal PowerPoint point size, directly writingsizeabsolute pt is more stable. Reverse formula:size_px = 目标pt × ref_height / (页高in×72)。 - Hard gate for text weight:
bolddefaultfalse; do not set alltexts[]tobold:truejust to "look more like a screenshot". Only titles, button titles, and key numbers/keywords should be bolded according to the original image; ordinary body text and explanatory paragraphs default to regular weight.layout_guard --strictwill report an error for suspected all-bold body text, unless the original image is indeed all bold and explicitly writesallow_all_bold_text:true。 - Multiple pages: gather each page's
slides[]into one deck.json and compose the whole deck at once. - Delivery: the final reply must give the clickable final
.pptxabsolute path; if a convenient copy was saved separately, also give both the original output path within RUN_ROOT and the copy path.
Scripts and Dependencies
| Script | What it does |
|---|---|
scripts/probe_palette.py |
Detect whether a page contains green, and recommend a safe matting background color |
scripts/chroma_key.py |
Preserve colors and lines / preserve shapeMatting: the green screen (or specified background color) becomes transparent without fading; the preset enhances anti-aliased edges and repairs small alpha breaks, working with --scale 2 supersampling to prevent horizontal/vertical lines and arcs from becoming ragged during matting |
scripts/slice_grid.py |
--grid N×N or --auto slice the transparent icon sheet into individual icons; optionally --components slice the frame image into movable frame parts by transparent connected regions; produce a manifest |
scripts/frame_parts_to_icons.py |
Optional frame slicing aid: map the bbox of frame_parts/icons_manifest.json to source image coordinates, generating entries in layout.icons[] that can be directly merged into role:"frame_part" , ensuring frame parts are assembled back according to the original frame.png layout |
scripts/layout_guard.py |
Validate the coordinate contract before compositing: whether the source image's actual dimensions andref_width/ref_height、source_bbox、x/y/w/h are consistent; can normalize thumbnail coordinates of the same width-to-height ratio back to source image pixels; does not perform page coverage height heuristic judgment |
scripts/placement_qa.py |
Draw the layout's icon/text bboxes back onto the source image and preview image, generating placement QA annotation images and source/preview overlay images |
scripts/visual_compare_qa.py |
After unifying the sizes of the source image and the final PPTX preview, output side-by-side images, overlay images, difference heatmaps, and diagnostic metrics, for GPT visual verification of whether text/icons are truly aligned |
scripts/compose_pptx.py |
Compose background + overall frame image (frame) + icons + texts into an editable .pptx according to layout/deck.json,--preview-dir output a preview; also supports frame_parts when the user requests frame slicing; by default does not use shapes to carry visual content |
- Dependencies:
python3+python-pptx、Pillow、numpy(if missing,pip3 install python-pptx pillow numpy)。 - If the input is an "image-based PPT", it is usually produced by GordenImagePPTGen ; for one-click "first generate images then convert to editable" → use GordenSuperPPTSkill。