libreoffice-impress について
libreoffice-impressは、UNO経由でLibreOffice Impressのプレゼンテーションを操作するPythonモジュールを提供します。構造化ターゲットによるスライド編集に加え、書き出しやスナップショットでの表示確認に対応します。
主な機能
- 01プレゼンテーションの作成と書き出し
- 02構造化ターゲットによるスライド編集
- 03テキスト、リスト、図形、メディアのパッチ
- 04表とグラフの更新
- 05スライドのスナップショット取得
活用シーン
- 01デッキに一連の編集を適用
- 02スライドのテキストと書式を更新
- 03プレゼンテーションをPDFまたはPPTXに書き出し
- 04編集後にスライドのレイアウトを確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dfk1352/ libreoffice-skills --skill libreoffice-impressインストール後、Claude Code で/libreoffice-impressを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/troubleshooting.mdscripts/colors.pyconstants.pyexceptions.pypatch_base.pysession.pyuno_bridge.pyscripts/impress/__init__.pycore.pyexceptions.pypatch.pysession.pysnapshot.pytargets.py詳細
LibreOffice Impress
UNO を使用した Impress プレゼンテーションの作業には、同梱の 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,
)
ターゲットの種類
| 種類 | 対応フィールド | 用途 |
|---|---|---|
slide | slide_index | スライドの一覧表示、削除、移動、複製、マスターページの適用 |
shape | slide_index と shape_name または shape_index | 汎用図形を読み取る/削除する |
image | slide_index と shape_name または shape_index | 画像を置換する/削除する |
table | slide_index と shape_name または shape_index | 表を更新する/削除する |
chart | slide_index と shape_name または shape_index | グラフを更新する/削除する |
media | slide_index と shape_name または shape_index | メディアオブジェクトを置換する/削除する |
text | スライドスコープのセレクターと text、after、before、occurrence | テキストを読み取る、置換する、削除する、または書式設定する |
list | スライドスコープのテキストセレクター | 構造化されたリストブロックを置換する/削除する |
insertion | スライドスコープのセレクターとアンカー | テキストまたはリストを挿入する |
notes | slide_index と任意のテキスト範囲 | 発表者ノートを読み取る/置換する |
master_page | master_name | 1つのマスターページを特定する |
解決ルール
- スライドインデックスは 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 で 1 枚のスライドに別のマスターを割り当て、隣接するスライドのマスターが以前のままであることを確認して検証済みです。
書式設定ペイロード: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"
)
注意:
- 書式設定フィールドを 1 つ以上設定する必要があります。
- 色には、色名または
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_slidedelete_slidemove_slideduplicate_slideinsert_textreplace_textformat_textinsert_listreplace_listinsert_text_boxinsert_shapedelete_iteminsert_imagereplace_imageinsert_tableupdate_tableinsert_chartupdate_chartinsert_mediareplace_mediaset_notesapply_master_pageset_master_background
パッチ値のルール
- 主なターゲットには
target.*フィールドを使用します。 apply_master_pageにはmaster.*フィールドを使用します。TextFormattingにはformat.*フィールドを使用します。ShapePlacementにはplacement.*フィールドを使用します。- リスト操作には
list.orderedと JSON のitemsを使用します。 itemsとdataは有効な JSON である必要があります。- 複数行のテキストまたは JSON には、
<<TAG ... TAG形式のヒアドキュメントブロックを使用できます。
モード
atomicは最初の失敗時に停止し、ファイルを元のバイト列に復元して、何も保存しません。best_effortは先行する成功済みの操作を維持し、後続の失敗を記録します。- リスト操作は操作の途中で保存やリセットを行わなくなったため、アトミックなロールバックに正しく参加します。
PatchApplyResult のフィールド:
modeoverall_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 始まりの値を使用すること。
- より長いフレーズを使用できる場合に、壊れやすい単語 1 つだけのテキストアンカーを使用すること。
- LibreOffice ネイティブのスライド複製後も図形名が完全に一致すると期待すること。UNO によって、
Name 1のように複製名が変更される場合があります。 itemsまたはdataのパッチフィールドに、不正な形式の JSON を指定すること。- 確認後に、キャプチャしたスナップショットをクリーンアップし忘れること。
session.close()の後にセッションメソッドを呼び出すこと。- 段落の配置オプション
"start"と"end"には、LibreOffice 26.2 以降が必要です。
コメント
Markdown 対応