表題のとおりです。PowerPointの既存スライドから特定セクションのスライドを抜き出して保存します。
詳しいソースはGithubに上げてあるので、興味がある人は見てください。
コツ
PowerPointのOLEオブジェクトは、"PowerPoint.Application"で取得できます。VBAマクロとしてプレゼンファイルに書くと
- プレゼンテーションそのものとマクロが紐付いてしまう(マクロがファイル内に記録されてしまう)
- プレゼンテーションをpptmで保存しなければならなくなる
ということで、自分は基本的に外部からOLEオブジェクトを使用してOfficeマクロを書いています。
あえてUWSCにする理由は
- 起動済みのPowerPointオブジェクトを指定してオブジェクト化する、`GETACTIVEOLEOBJ'関数がある
- セレクトボックスなどのごく簡易的なGUIが揃っている
ということで、今回はUWSCを使ってPowerPointのスライドを叩くことにしました。
必要なメソッドとか。
プレゼンテーション内のセクションに関する情報を得る場合は、Presentation.SectionProperties()オブジェクトを使用します。このオブジェクトは他のオブジェクトと違ってコンテナ構造になっていないため、
- SectionProperties.Countプロパティでセクションの数を取得
- SectionProperties.Name()メソッドでセクションの名前を取得
- SectionProperties.FirstSlide()メソッドでセクションの先頭スライドのスライド番号を取得
- SectionProperties.SlidesCount()メソッドでセクション内のスライド個数を取得
という形となります。
最初のスライドとセクション内のスライド数がわかったら、あとはSlides.Range()メソッドでセクションをすべて選択し、Copyメソッドを呼べばOK。
新しいプレゼンテーションファイルを作って貼り付け、Presenration.CreateVideo()メソッドで保存すればOK。
というわけでコード。
というわけでコードです。今回はPowerPointに関する定型的な処理をとりあえずモジュール化しました。
//
// PowerPoint関係の処理を詰め込んだモジュール
//
MODULE PPT
DIM app
//
// コンストラクタ
//
PROCEDURE PPT()
COM_ERR_IGN
app = GETACTIVEOLEOBJ( "PowerPoint.Application")
COM_ERR_RET
IF COM_ERR_FLG THEN app = NULL
FEND
//
// PowerPointオブジェクトを取得する
// 戻り値…PowerPoint。開かれていなかった場合NULL
//
FUNCTION GET()
RESULT = app
FEND
//
// 開いている全てのPowerPointファイルの中から一つを選択して返す
// 戻り値…選択されたPowerPointファイル。
// PowerPointが開いていない場合、選択がキャンセルされた場合はNULLを返す
//
FUNCTION CHOICEPRESENTATION()
DIM app = GET()
DIM files[0]
COM_ERR_IGN
DIM count = GETOLEITEM( app.presentations )
COM_ERR_RET
IFB count <= 0 OR COM_ERR_FLG THEN
RESULT = NULL
ELSE
RESIZE(files, count)
FOR i = 0 TO count - 1
files[i] = ALL_OLE_ITEM[i].name
NEXT
// ファイルを選択
DIM file = SLCTBOX(SLCT_CMB + SLCT_STR, 0, "ファイルを選択", files)
IF file = "-1" THEN RESULT = NULL ELSE RESULT = app.presentations(file)
ENDIF
FEND
//
// プレゼンテーションの中からセクションを選択する
// presentation…セクションを検索するプレゼンテーションファイル
// 戻り値…選択されたセクションのインデックス
// セクションが無い場合は-1、選択がキャンセルされた場合は-2を返す
//
FUNCTION CHOICESECTION(presentation)
DIM sections[0]
DIM count = presentation.sectionProperties.count
IFB count <= 0 THEN
RESULT = -1
ELSE
RESIZE(sections, count)
FOR i = 1 TO count
sections[i] = presentation.sectionProperties.name(i)
NEXT
// セクションを選択
DIM sel = SLCTBOX(SLCT_CMB + SLCT_NUM, 0, "セクションを選択", sections)
IF sel = "-1" THEN RESULT = -2 ELSE RESULT = sel
ENDIF
FEND
ENDMODULE
//
// 指定ファイル内の選択したセクションを抜き出し、動画として保存
//
CALL PPT.uws
DIM app = PPT.GET()
// プレゼンテーション・セクションを選択
DIM file = PPT.CHOICEPRESENTATION()
IF file = NULL THEN EXIT
DIM index = PPT.CHOICESECTION(file) + 1
IF index <= 0 THEN EXIT
// 最初と最後のスライド番号を取得
DIM first = file.sectionProperties.firstSlide(index)
DIM count = file.sectionProperties.slidesCount(index)
DIM name = file.sectionProperties.name(index)
DIM last = first + count - 1
PRINT "Pickup:" + first + " TO " + last
// コピー
DIM newppt = app.presentations.add(TRUE)
DIM r = SAFEARRAY(1, count)
FOR i = 1 TO count
r[i] = first + i - 1
NEXT
file.slides.range(r).copy()
newppt.slides.paste()
//
newppt.createVideo(GET_CUR_DIR + "\" + name + ".mp4", -1)
PRINT name + ".mp4 Save End!"
とりあえず注意すべき所はふたつかな。
Slides.Range()メソッド
Slides.Range()メソッドの引数は、VBArrayです。、UWSCではSafeArrayになります。格納する値もコピーするスライドの最初と最後のスライドインデックスから、選択するスライドのインデックスをすべて指定になりますので、注意が必要です。
Presentation.CreateVideoメソッド
Presentation.CreateVideoメソッドの第二引数は、各スライドに指定した画面切り替えのタイミングを使うかどうかで、データ型はBooleanです。
しかしこの場合、TRUEまたはFALSEではなく、数値を指定します。-1がTrueで、それ以外がFalse。確かこの辺はVBの伝統ですね。
ほかはたぶんUWSCの基礎がわかっていれば迷うことはなさそう。