skills/ppt-station-skill/reference/layout-image-text.md
wangyitong a65adcc2e5 Initial commit: merged, deduplicated, and vetted skill collection
Sources: extracted from two upstream archives (skill-repo, skills-main),
merged with the following policy:

- 15 broken symlinks (pointing to /Users/jameslee/.cc-switch/skills or
  ../../.agents/skills on a foreign machine) discarded
- 3 real name collisions with identical content (ai-pair, ifind-http-api,
  zhipu-websearch) kept as one copy
- Functional overlaps deduped keeping the strongest variant:
  - docx family: kept docx (official, full toolchain) + docx-cn
    (GB/T 9704 Chinese official-document constants),
    dropped docx_writer (no scripts, name collided with docx)
  - humanizer family: kept humanizer-zh (6 zh reference docs),
    dropped humanizer (en, redundant for CN workflow)
- Skills that only ran in a foreign environment removed:
  ablemind-ops, app-publish, hlb-design-system, openclaw-adj-skill,
  claude-driver
- alphapai excluded from this public repo because its SKILL.md hard-coded
  live credentials

Result: 25 skills, 572 files, ~7.5 MB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:47:12 +08:00

12 KiB
Raw Blame History

Layout: image_text — 图片+文字(左右可切换)

幻灯片尺寸: 13.333 × 7.5 英寸 | 边距: 0.6 英寸 | 内容宽: 12.133 英寸


用途

产品展示、团队介绍、案例分析、公司介绍、基金经理简介。


ASCII 线框图

变体 A左图右文image_side="left"

┌─────────────────────────────────────────────────────────────┐
│  [标题]                                     y=0.25          │
│  ▬▬ (accent 装饰线)                         y=0.90          │
│                                                              │
│  ┌──────────────────────────┐  ┌──────────────────────────┐ │
│  │                          │  │  [副标题/小标签]          │ │
│  │      [ 图 片 ]           │  │                          │ │
│  │                          │  │  [正文段落...]            │ │
│  │   (fill=bg_dark或图片)   │  │  正文继续...              │ │
│  │                          │  │                          │ │
│  │                          │  │  ● 要点一                 │ │
│  │                          │  │  ● 要点二                 │ │
│  │                          │  │  ● 要点三                 │ │
│  └──────────────────────────┘  └──────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

变体 B右图左文image_side="right"

镜像翻转,文字在左,图片在右。

变体 C无实际图片用色块+数据代替图片区)

│  ┌──────────────────────────┐  ┌──────────────────────────┐ │
│  │   bg_dark 深色区域        │  │  [文字内容]               │ │
│  │                          │  │                          │ │
│  │      大数字强调           │  │                          │ │
│  │     "380亿"               │  │                          │ │
│  │   [规模标签]              │  │                          │ │
│  │                          │  │                          │ │
│  └──────────────────────────┘  └──────────────────────────┘ │

精确坐标标注

固定元素

元素 x y w h 字号 颜色
页面标题 0.60 0.25 12.133 0.60 title_size-2 text_dark
装饰线 0.60 0.90 2.00 0.04 accent

左右分栏50/50 分割)

image_side = "left"(默认)

分割线 x = 0.60 + 12.133 * 0.50 + 0.15 = 7.167(以图片区右边界为准)

图片区(左侧):
  img_x = 0.60
  img_y = 1.10
  img_w = 5.667   # 12.133 * 0.50 - 0.40(间距)
  img_h = 6.00    # 7.5 - 1.10 - 0.40(底部留白)

文字区(右侧):
  text_x = 7.067  # img_x + img_w + 0.80(间距)
  text_y = 1.10
  text_w = 5.667  # 对称
  text_h = 6.00

间距: 图片区与文字区之间固定留 0.80" 间距(分别各 0.40"

图片区内容(当无实际图片文件,用深色背景 + 大文字代替)

元素 x y w h 字号 颜色 对齐
图片背景块 img_x img_y img_w img_h bg_dark
大数字(可选) img_x img_y+1.50 img_w 1.50 72pt accent
数字标签(可选) img_x img_y+3.10 img_w 0.50 body_size+2 text_light
来源标注(可选) img_x img_y+3.70 img_w 0.40 caption_size text_muted

文字区内部结构

元素 x y相对 text_y w h 字号 颜色 对齐
小标签/类型 text_x +0 text_w 0.35 caption_size accent
副标题 text_x +0.40 text_w 0.65 subtitle_size text_dark
accent 短横线 text_x +1.10 1.50 0.04 accent
正文段落 text_x +1.25 text_w 2.20 body_size text_dark
要点列表起始 y text_x +3.55 text_w body_size text_dark
底部标注/签名 text_x +5.50 text_w 0.40 caption_size text_muted

要点列表行(每行):

add_rect(slide, text_x, bullet_y+0.12, 0.08, 0.08, fill=accent)  # 小方块bullet
add_text(slide, bullet_text, x=text_x+0.20, y=bullet_y, w=text_w-0.20, h=0.45,
         font_size=body_size, color=text_dark)

宽度变体非严格50/50

变体名 图片区 文字区 适用场景
50/50 5.667" 5.667" 默认,图文均衡
40/60 4.453" 7.080" 文字内容多时
60/40 7.080" 4.453" 图片内容丰富时

数据接口

data = {
    "title": str,                        # 页面标题
    "image_side": "left" | "right",      # 图片在哪侧,默认 "left"
    "image_path": str | None,            # 图片文件路径None 则用色块代替
    "image_fill_color": str,             # 当 image_path=None 时,色块颜色变量名,默认 "bg_dark"
    # 图片区(无实际图片时)的内容
    "image_number": str | None,          # 大数字(如 "380亿"),可选
    "image_number_label": str | None,    # 数字标签(如 "资产规模"),可选
    # 文字区内容
    "tag": str | None,                   # 小标签文字(如 "团队介绍"),可选
    "text_title": str,                   # 副标题(如人名或章节小标题)
    "text_body": str,                    # 正文段落
    "bullets": list[str] | None,        # 要点列表,可选
    "footnote": str | None,             # 底部小注,可选
    # 布局
    "split_ratio": float,               # 图片区占内容宽比例,默认 0.50
    "variant": "default" | "dark_image", # 默认变体或深色图片区变体
}

实现伪代码

def layout_image_text(slide, data, theme):
    from pptx.util import Inches
    m = theme["margin"]
    sw, sh = 13.333, 7.5
    cw = sw - 2 * m

    set_slide_bg(slide, theme["bg_light"])
    add_text(slide, data["title"],
             x=m, y=0.25, w=cw, h=0.60,
             font_size=theme["title_size"]-2, color=theme["text_dark"],
             bold=True, font_name=theme["header_font"])
    add_rect(slide, m, 0.90, 2.0, 0.04, fill=theme["accent"])

    ratio = data.get("split_ratio", 0.50)
    inner_gap = 0.40    # 每侧留出的间距
    img_w = cw * ratio - inner_gap
    txt_w = cw * (1 - ratio) - inner_gap
    area_y = 1.10
    area_h = sh - area_y - 0.40

    img_side = data.get("image_side", "left")
    if img_side == "left":
        img_x = m
        txt_x = m + img_w + inner_gap * 2
    else:
        txt_x = m
        img_x = m + txt_w + inner_gap * 2

    # 图片区
    if data.get("image_path"):
        # 插入实际图片
        from pptx.util import Inches
        slide.shapes.add_picture(
            data["image_path"],
            Inches(img_x), Inches(area_y),
            Inches(img_w), Inches(area_h)
        )
    else:
        # 深色色块代替
        img_color = theme.get(
            data.get("image_fill_color", "bg_dark"), theme["bg_dark"])
        add_rect(slide, img_x, area_y, img_w, area_h, fill=img_color)
        if data.get("image_number"):
            add_text(slide, data["image_number"],
                     x=img_x, y=area_y+1.50, w=img_w, h=1.50,
                     font_size=72, color=theme["accent"],
                     bold=True, align="center", font_name=theme["header_font"])
        if data.get("image_number_label"):
            add_text(slide, data["image_number_label"],
                     x=img_x, y=area_y+3.10, w=img_w, h=0.50,
                     font_size=theme["body_size"]+2, color=theme["text_light"],
                     align="center", font_name=theme["body_font"])

    # 文字区
    ty = area_y
    if data.get("tag"):
        add_text(slide, data["tag"],
                 x=txt_x, y=ty, w=txt_w, h=0.35,
                 font_size=theme["caption_size"], color=theme["accent"],
                 font_name=theme["body_font"])
        ty += 0.40
    if data.get("text_title"):
        add_text(slide, data["text_title"],
                 x=txt_x, y=ty, w=txt_w, h=0.65,
                 font_size=theme["subtitle_size"], color=theme["text_dark"],
                 bold=True, font_name=theme["header_font"])
        ty += 0.70
        add_rect(slide, txt_x, ty, 1.50, 0.04, fill=theme["accent"])
        ty += 0.15
    if data.get("text_body"):
        add_text(slide, data["text_body"],
                 x=txt_x, y=ty, w=txt_w, h=2.20,
                 font_size=theme["body_size"], color=theme["text_dark"],
                 font_name=theme["body_font"])
        ty += 2.30
    if data.get("bullets"):
        for bullet in data["bullets"]:
            add_rect(slide, txt_x, ty+0.12, 0.08, 0.08, fill=theme["accent"])
            add_text(slide, bullet,
                     x=txt_x+0.20, y=ty, w=txt_w-0.20, h=0.45,
                     font_size=theme["body_size"], color=theme["text_dark"],
                     font_name=theme["body_font"])
            ty += 0.50
    if data.get("footnote"):
        add_text(slide, data["footnote"],
                 x=txt_x, y=area_y+area_h-0.40, w=txt_w, h=0.40,
                 font_size=theme["caption_size"], color=theme["text_muted"],
                 font_name=theme["body_font"])

设计要点

  1. 图片区与文字区 各占约 50%,左右可切换,保持视觉多样性
  2. 无图片时bg_dark 深色色块代替,加大数字,效果与图片一样震撼
  3. 文字区左上角小标签"团队介绍"/"案例分析")用 accent 色,比副标题小一级
  4. 文字区 accent 短横线 位于副标题与正文之间,宽 1.50",与页面标准装饰线一致
  5. 图片填充方式: 用 add_picture 时建议 fill 模式(拉伸填满),保持比例

测试数据示例

# 示例1基金经理介绍无实际图片用深色块代替
data = {
    "title": "投资管理团队",
    "image_side": "left",
    "image_path": None,
    "image_fill_color": "bg_dark",
    "image_number": "26年",
    "image_number_label": "平均投资经验",
    "tag": "首席投资官",
    "text_title": "张明远",
    "text_body": "毕业于北京大学经济学院CFA持证人具有26年资本市场投资经验。历任多家顶级资产管理机构投资总监。",
    "bullets": [
        "主导管理资产规模超 3,800 亿元",
        "年化超额收益 4.2%2015-2024",
        "荣获中国养老金投资十佳基金经理",
    ],
    "footnote": "截至 2024 年 12 月 31 日",
}

# 示例2实际图片如产品截图或场景照片
data = {
    "title": "养老社区实地调研",
    "image_side": "right",
    "image_path": "/path/to/community_photo.jpg",
    "tag": "案例分析",
    "text_title": "北京·夕阳红养老社区",
    "text_body": "项目总建筑面积 12 万平方米,设计床位 1,200 张,配套医疗、康复、餐饮全覆盖。",
    "bullets": [
        "入住率 94%,位居北京市前三",
        "REITs 上市,估值 35 亿元",
        "年化租金回报率 5.8%",
    ],
}