mcpField
L
libreoffice-impress

libreoffice-impress

github.com/dfk1352文档处理7107 次安装3 天前更新
代码仓库

关于 libreoffice-impress

libreoffice-impress 提供通过 UNO 操作 LibreOffice Impress 演示文稿的 Python 模块。它支持用结构化目标编辑幻灯片及其内容,并可导出文件和生成幻灯片快照以检查视觉效果。

主要功能

  1. 01创建并导出演示文稿
  2. 02通过结构化目标编辑幻灯片
  3. 03修补文本、列表、形状和媒体
  4. 04更新表格和图表
  5. 05生成幻灯片快照

适用场景

  1. 01批量应用一组演示文稿修改
  2. 02更新幻灯片文本和格式
  3. 03将演示文稿导出为 PDF 或 PPTX
  4. 04编辑后检查幻灯片布局

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dfk1352/libreoffice-skills --skill libreoffice-impress

安装后在 Claude Code 中输入/libreoffice-impress确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
troubleshooting.md
scripts/
colors.py
constants.py
exceptions.py
patch_base.py
session.py
uno_bridge.py
scripts/impress/
__init__.py
core.py
exceptions.py
patch.py
session.py
snapshot.py
targets.py

详细介绍

LibreOffice Impress

使用捆绑的 impress 模块处理由 UNO 支持的 Impress 演示文稿。 所有路径都必须是绝对路径。捆绑模块位于此技能目录下的 scripts/ 中,因此请设置 PYTHONPATH=<skill_base_dir>/scripts。 如果出现设置或运行时问题,请查看 references/troubleshooting.md。

API 范围

# Non-session utilities
create_presentation(path)
get_slide_count(path)
export_presentation(path, output_path, export_format)   # formats: "pdf", "pptx"
snapshot_slide(doc_path, slide_index, output_path, width=1280, height=720)

# Session (primary editing API)
ImpressSession(path) -> context manager

ImpressSession methods:
  get_slide_count() -> int
  get_slide_inventory(target: ImpressTarget) -> dict[str, object]
  add_slide(index=None, layout="BLANK")
  delete_slide(target: ImpressTarget)
  move_slide(target: ImpressTarget, to_index)
  duplicate_slide(target: ImpressTarget)
  delete_item(target: ImpressTarget)
  read_text(target: ImpressTarget) -> str
  insert_text(text, target: ImpressTarget | None = None)
  replace_text(target: ImpressTarget, new_text)
  format_text(target: ImpressTarget, formatting: TextFormatting)
  insert_list(items: list[ListItem], ordered: bool, target: ImpressTarget | None = None)
  replace_list(target: ImpressTarget, items: list[ListItem], ordered: bool | None = None)
  insert_text_box(slide: ImpressTarget, text, placement: ShapePlacement, name=None)
  insert_shape(slide: ImpressTarget, shape_type, placement: ShapePlacement, fill_color=None, line_color=None, name=None)
  insert_image(slide: ImpressTarget, image_path, placement: ShapePlacement, name=None)
  replace_image(target: ImpressTarget, image_path=None, placement: ShapePlacement | None = None)
  insert_table(slide: ImpressTarget, rows, cols, placement: ShapePlacement, data=None, name=None)
  update_table(target: ImpressTarget, data)
  insert_chart(slide: ImpressTarget, chart_type, data, placement: ShapePlacement, title=None, name=None)
  update_chart(target: ImpressTarget, chart_type=None, data=None, placement: ShapePlacement | None = None, title=None)
  insert_media(slide: ImpressTarget, media_path, placement: ShapePlacement, name=None)
  replace_media(target: ImpressTarget, media_path=None, placement: ShapePlacement | None = None)
  set_notes(target: ImpressTarget, text)
  get_notes(target: ImpressTarget) -> str
  list_master_pages() -> list[str]
  apply_master_page(target: ImpressTarget, master_target: ImpressTarget)
  set_master_background(target: ImpressTarget, color)
  import_master_page(template_path) -> MasterPageImportResult
  patch(patch_text, mode="atomic") -> PatchApplyResult
  export(output_path, export_format)
  reset()
  close(save=True)

# Standalone patch utility
patch(path, patch_text, mode="atomic") -> PatchApplyResult

结构化目标:ImpressTarget

from impress import ImpressTarget

ImpressTarget(
    kind=(
        "slide" | "shape" | "text" | "table" | "chart" |
        "media" | "notes" | "master_page" | "list" | "insertion" | "image"
    ),
    slide_index=None,
    shape_name=None,
    shape_index=None,
    shape_type=None,
    placeholder=None,
    text=None,
    after=None,
    before=None,
    occurrence=None,
    master_name=None,
)
目标类型
类型支持的字段用途
slideslide_index幻灯片清单、删除、移动、复制、应用母版页
shapeslide_index 加上 shape_name 或 shape_index读取/删除一个通用形状
imageslide_index 加上 shape_name 或 shape_index替换/删除一张图片
tableslide_index 加上 shape_name 或 shape_index更新/删除一个表格
chartslide_index 加上 shape_name 或 shape_index更新/删除一个图表
mediaslide_index 加上 shape_name 或 shape_index替换/删除一个媒体对象
text幻灯片范围内的选择器,加上 text、after、before、occurrence读取、替换、删除或设置文本格式
list幻灯片范围内的文本选择器替换/删除一个结构化列表块
insertion幻灯片范围内的选择器,加上锚点插入文本或列表
notesslide_index 加上可选的文本范围读取或替换演讲者备注
master_pagemaster_name解析一个母版页
解析规则
  • 幻灯片索引从 0 开始。
  • shape_name 和 shape_index 不能同时使用。
  • placeholder 目标支持 title、body 和 subtitle 等明确值。
  • 使用 after 和 before 缩小单个已解析含文本对象中的文本或列表解析范围。
  • 对于对象目标,优先使用 shape_name;仅当幻灯片顺序稳定时才使用 shape_index。
  • delete_item() 接受任何非幻灯片删除目标:text、notes、list、shape、image、table、chart 或 media。
  • apply_master_page() 支持针对单张幻灯片操作。已通过 UNO 验证:为一张幻灯片指定不同的母版,并确认相邻幻灯片仍保留原有母版。

格式载荷:TextFormatting

from impress import TextFormatting

TextFormatting(
    bold=None,
    italic=None,
    underline=None,
    font_name=None,
    font_size=None,
    color=None,          # named color or integer
    align=None,          # "left" | "center" | "right" | "justify" | "start" | "end"
)

备注:

  • 必须至少设置一个格式字段。
  • 颜色可使用命名颜色或 0xRRGGBB 整数。
  • 段落对齐方式通过与字符样式相同的格式载荷应用。

几何载荷:ShapePlacement

from impress import ShapePlacement

ShapePlacement(x_cm=1.0, y_cm=2.0, width_cm=8.0, height_cm=4.0)
  • 几何值的单位为厘米。
  • 宽度和高度必须为正数。

列表项

from impress import ListItem

ListItem(text="Confirm scope", level=0)
  • level 表示从 0 开始的嵌套层级。
  • 嵌套层级不能跳级。
  • 列表编辑是结构化操作;不要手动添加 - 前缀。
  • 无头模式下的快照渲染可能不会显示项目符号,即使列表元数据正确无误。

补丁 DSL

使用 patch() 或 session.patch() 按顺序应用操作。

[operation]
type = replace_text
target.kind = text
target.slide_index = 2
target.placeholder = body
target.text = Quarterly revenue rose 18%
new_text = Quarterly revenue rose 21%

[operation]
type = insert_list
target.kind = insertion
target.slide_index = 2
target.shape_name = Agenda Box
target.after = Action Items
list.ordered = false
items <<JSON
[
  {"text": "Confirm scope", "level": 0},
  {"text": "Review outputs", "level": 0},
  {"text": "Update notes", "level": 1}
]
JSON

[operation]
type = delete_item
target.kind = chart
target.slide_index = 4
target.shape_name = Disposable Chart
支持的操作类型
  • add_slide
  • delete_slide
  • move_slide
  • duplicate_slide
  • insert_text
  • replace_text
  • format_text
  • insert_list
  • replace_list
  • insert_text_box
  • insert_shape
  • delete_item
  • insert_image
  • replace_image
  • insert_table
  • update_table
  • insert_chart
  • update_chart
  • insert_media
  • replace_media
  • set_notes
  • apply_master_page
  • set_master_background
补丁值规则
  • 主目标使用 target.* 字段。
  • apply_master_page 使用 master.* 字段。
  • TextFormatting 使用 format.* 字段。
  • ShapePlacement 使用 placement.* 字段。
  • 列表操作使用 list.ordered 和 JSON items。
  • items 和 data 必须是有效的 JSON。
  • 多行文本或 JSON 支持使用 <<TAG ... TAG heredoc 块。
模式
  • atomic 在首次失败时停止,还原原始文件字节,且不保存任何内容。
  • best_effort 保留先前成功的操作,并记录后续失败。
  • 列表操作会正确参与原子回滚,因为它们不再在操作过程中存储或重置。

PatchApplyResult 字段:

  • mode
  • overall_status = "ok" | "partial" | "failed"
  • operations = PatchOperationResult 列表
  • document_persisted

对于独立的 patch(path, ...),document_persisted 表示更改已保存到磁盘。对于 session.patch(...),它表示补丁在当前打开的会话状态中产生了成功的变更。

示例:在会话中编辑演示文稿

from pathlib import Path

from impress import (
    ImpressSession,
    ImpressTarget,
    ListItem,
    ShapePlacement,
    TextFormatting,
)
from impress.core import create_presentation

output = str(Path("test-output/demo.odp").resolve())
create_presentation(output)

with ImpressSession(output) as session:
    session.add_slide(layout="TITLE_AND_CONTENT")
    session.replace_text(
        ImpressTarget(kind="text", slide_index=1, placeholder="title"),
        "Executive Summary",
    )
    session.replace_text(
        ImpressTarget(kind="text", slide_index=1, placeholder="body"),
        "Quarterly revenue rose 18%.",
    )
    session.insert_text_box(
        ImpressTarget(kind="slide", slide_index=1),
        "Action Items",
        ShapePlacement(1.0, 5.0, 10.0, 4.0),
        name="Agenda Box",
    )
    session.insert_list(
        [
            ListItem(text="Confirm scope", level=0),
            ListItem(text="Review output", level=0),
            ListItem(text="Update packaging", level=1),
        ],
        ordered=False,
        target=ImpressTarget(
            kind="insertion",
            slide_index=1,
            shape_name="Agenda Box",
            after="Action Items",
        ),
    )
    session.format_text(
        ImpressTarget(
            kind="text",
            slide_index=1,
            placeholder="body",
            text="Quarterly revenue rose 18%.",
        ),
        TextFormatting(bold=True, align="center"),
    )

示例:修补现有演示文稿

from impress import patch

result = patch(
    "/abs/path/demo.odp",
    """
    [operation]
    type = replace_text
    target.kind = text
    target.slide_index = 1
    target.placeholder = body
    new_text = Quarterly revenue rose 21%.

    [operation]
    type = insert_media
    target.kind = slide
    target.slide_index = 1
    media_path = /abs/path/demo.wav
    placement.x_cm = 1.0
    placement.y_cm = 9.0
    placement.width_cm = 5.0
    placement.height_cm = 3.0
    name = Demo Media

    [operation]
    type = delete_item
    target.kind = media
    target.slide_index = 1
    target.shape_name = Demo Media
    """,
    mode="best_effort",
)

print(result.overall_status)

快照

from pathlib import Path
from impress import snapshot_slide

result = snapshot_slide(doc_path, 0, "/tmp/slide1.png")
print(result.file_path, result.width, result.height)
Path(result.file_path).unlink(missing_ok=True)   # clean up used snapshots

在编辑文本、更改母版页、调整表格或图表位置,或执行其他视觉操作后,可使用快照验证幻灯片布局。

  • TITLE_AND_CONTENT 等布局会在 add_slide() 后立即提供可写的标题/正文占位符。
  • get_slide_inventory() 可能会包含名称为空的形状;请使用返回的清单,查找幻灯片上可用的持久化标识符。
  • 在持久化清单中,LibreOffice 可能会规范化用户提供的形状名称,例如将空格替换为下划线。

常见错误

  • 传入相对路径;面向 UNO 的 Impress API 要求使用绝对文件路径。
  • 使用从 1 开始的幻灯片索引。
  • 在有更完整短语可用时,使用容易出错的单词文本锚点。
  • 使用 LibreOffice 原生功能复制幻灯片后,仍期望形状名称完全不变;UNO 可能会重命名副本,例如将其改为 Name 1。
  • 在 items 或 data 补丁字段中提供格式错误的 JSON。
  • 检查后忘记清理已捕获的快照。
  • 在调用 session.close() 后调用会话方法。
  • "start" 和 "end" 段落对齐选项需要 LibreOffice 26.2+。

评论

支持 Markdown