PythonでPowerPointプレゼンテーションをビデオに変換

概要

PowerPointまたはOpenDocumentのプレゼンテーションをビデオに変換すると、プレゼンテーションアプリケーションを開かずにビデオプレーヤーで内容を視聴できます。Aspose.Slides for Python via Java は、プレゼンテーションのアニメーションとトランジションを画像フレームにレンダリングします。FFmpeg のような別のエンコーダーが、これらのフレームをビデオファイルに結合します。

PowerPointをビデオに変換

変換は 2 つの段階で行われます。選択したフレームレートで PNG フレームを生成し、次に画像シーケンスを MP4 にエンコードします。アニメーションのタイミングを保持するため、両方の段階で同じフレームレートを使用してください。

サンプルを実行する前に:

  1. Aspose.Slides for Python via Java をセットアップします。
  2. FFmpeg をダウンロードし、実行可能ファイルを PATH に配置します。サンプルでは libx264 エンコーダーを含むビルドを使用しています。
  3. 書き込み可能なディレクトリで以下の Python コードを実行します。

このサンプルは、入口と退出のアニメーションを持つ笑顔のシェイプを作成し、30 FPS でフレームをレンダリングし、FFmpeg を呼び出して output.mp4 を作成します。新しいフレームディレクトリを使用することで、以前の実行で生成されたフレームがビデオに含まれることを防ぎます。

import shutil
import subprocess
import tempfile
from pathlib import Path

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import EffectPresetClassType, EffectSubtype, EffectTriggerType, EffectType, ImageFormat, Presentation, PresentationAnimationsGenerator, PresentationPlayer, ShapeType

fps = 30
frames_directory = Path(tempfile.mkdtemp(prefix="video_frames_", dir="."))
frame_count = 0

def save_frame(sender, arguments):
    global frame_count
    frame_path = frames_directory / f"frame_{frame_count:06d}.png"
    frame = arguments.getFrame()
    try:
        frame.save(str(frame_path), ImageFormat.Png)
    finally:
        frame.dispose()
    frame_count += 1

presentation = Presentation()
try:
    slide = presentation.getSlides().get_Item(0)
    smile = slide.getShapes().addAutoShape(ShapeType.SmileyFace, 110, 20, 500, 500)
    sequence = slide.getTimeline().getMainSequence()
    entrance = sequence.addEffect(smile, EffectType.Fly, EffectSubtype.TopLeft, EffectTriggerType.AfterPrevious)
    entrance.getTiming().setDuration(2.0)
    exit_effect = sequence.addEffect(smile, EffectType.Fly, EffectSubtype.BottomRight, EffectTriggerType.AfterPrevious)
    exit_effect.setPresetClassType(EffectPresetClassType.Exit)
    exit_effect.getTiming().setDuration(2.0)

    generator = PresentationAnimationsGenerator(presentation)
    try:
        player = PresentationPlayer(generator, fps)
        try:
            callback = jpype.JProxy("com.aspose.slides.PresentationPlayer$FrameTick", dict(invoke=save_frame))
            player.setFrameTick(callback)
            generator.run(presentation.getSlides())
        finally:
            player.dispose()
    finally:
        generator.dispose()
finally:
    presentation.dispose()

ffmpeg = shutil.which("ffmpeg")
if frame_count == 0:
    print("No frames were generated.")
elif ffmpeg is None:
    print(f"FFmpeg was not found on PATH. PNG frames are available in {frames_directory}.")
else:
    input_pattern = str(frames_directory / "frame_%06d.png")
    command = [ffmpeg, "-n", "-framerate", str(fps), "-start_number", "0", "-i", input_pattern, "-vf", "pad=ceil(iw/2)*2:ceil(ih/2)*2", "-c:v", "libx264", "-pix_fmt", "yuv420p", "output.mp4"]
    result = subprocess.run(command, check=False)
    if result.returncode == 0:
        print("Saved output.mp4")
    else:
        print(f"FFmpeg failed with exit code {result.returncode}. Frames are available in {frames_directory}.")

既存のファイルを変換するには、Presentation をファイルパスで初期化し、シェイプ作成とアニメーション作成のステートメントを省略します。

FFmpeg コマンドは番号付きのimage sequence を読み取り、奇数の寸法を偶数にパッドし、yuv420p ピクセルフォーマットで H.264 ビデオを書き出します。-n オプションは既存の出力ファイルの上書きを防止します。生成された PNG ファイルはフレームディレクトリに残りますので、不要になったら削除してください。

動画エフェクト

アニメーションはスライドオブジェクトの表示、移動、または消失を制御します。トランジションはスライド間の切り替えを制御します。これらのエフェクトは動画フレームを生成する前に追加してください。

以下をご覧ください: PowerPoint Animation, Shape Animation, Shape Effects, および Slide Transitions

スライド トランジションを追加

以下の自己完結型サンプルは、2 枚のスライドからなるプレゼンテーションを作成します。2 枚目のスライドはマゼンタ背景でプッシュトランジションが設定されています。プレゼンテーションを保存し、上記のフレーム生成サンプルの入力として使用してください。

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import BackgroundType, FillType, Presentation, SaveFormat, ShapeType, TransitionType

Color = jpype.JClass("java.awt.Color")

presentation = Presentation()
try:
    first_slide = presentation.getSlides().get_Item(0)
    first_slide.getShapes().addAutoShape(ShapeType.SmileyFace, 110, 20, 500, 500)
    new_slide = presentation.getSlides().addEmptySlide(first_slide.getLayoutSlide())
    new_slide.getBackground().setType(BackgroundType.OwnBackground)
    new_slide.getBackground().getFillFormat().setFillType(FillType.Solid)
    new_slide.getBackground().getFillFormat().getSolidFillColor().setColor(Color.MAGENTA)
    new_slide.getSlideShowTransition().setType(TransitionType.Push)
    presentation.save("transition.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

段落にアニメーションを付ける

テキストは段落ごとに表示できます。このサンプルは、3 つの段落を作成し、順次フェードインの入口エフェクトを適用し、各エフェクトは前のエフェクトから 1 秒遅れます。保存した paragraphs.pptx ファイルを動画変換サンプルの入力として使用してください。

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import EffectSubtype, EffectTriggerType, EffectType, Paragraph, Portion, Presentation, SaveFormat, ShapeType

presentation = Presentation()
try:
    slide = presentation.getSlides().get_Item(0)
    shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 210, 120, 300, 300)
    shape.addTextFrame("")
    paragraphs = shape.getTextFrame().getParagraphs()
    paragraphs.clear()
    sequence = slide.getTimeline().getMainSequence()
    texts = ["Aspose.Slides for Python via Java", "Convert presentation text to video", "Paragraph by paragraph"]

    for text in texts:
        paragraph = Paragraph()
        portion = Portion(text)
        paragraph.getPortions().add(portion)
        paragraphs.add(paragraph)
        effect = sequence.addEffect(paragraph, EffectType.Fade, EffectSubtype.None_, EffectTriggerType.AfterPrevious)
        effect.getTiming().setTriggerDelayTime(1.0)
        effect.getTiming().setDuration(1.0)

    presentation.save("paragraphs.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

動画変換クラス

PresentationAnimationsGenerator はスライドのアニメーションイベントを生成します。プレゼンテーションから構築すると、プレゼンテーションのスライドサイズがフレームに使用されます。setDefaultDelay を使用してデフォルトの遅延をミリ秒で設定します。

PresentationPlayer はコンストラクタで指定されたフレームレートで生成されたアニメーションをサンプリングします。JPype を介して setFrameTick で Python コールバックを登録し、run を呼び出してフレームを生成します。最初のサンプルは独自のゼロベースカウンタを使用し、ファイル名が FFmpeg の入力シーケンスと一致するようにしています。

個々のアニメーション状態については、setNewAnimation でコールバックを登録します。コールバックは、任意の時間に位置付け可能なアニメーションプレイヤーを受け取ります。以下のサンプルは、生成された各アニメーションの最初と最後のフレームをユニークなファイル名で保存します。

from pathlib import Path

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import EffectSubtype, EffectTriggerType, EffectType, ImageFormat, Presentation, PresentationAnimationsGenerator, ShapeType

output_directory = Path("animation_states")
output_directory.mkdir(exist_ok=True)
animation_index = 0

def save_animation_states(animation_player):
    global animation_index
    duration = animation_player.getDuration()
    print(f"Animation {animation_index}: {duration} milliseconds")
    for label, position in [("first", 0.0), ("last", duration)]:
        animation_player.setTimePosition(position)
        frame = animation_player.getFrame()
        try:
            frame_path = output_directory / f"animation_{animation_index:04d}_{label}.png"
            frame.save(str(frame_path), ImageFormat.Png)
        finally:
            frame.dispose()
    animation_index += 1

presentation = Presentation()
try:
    slide = presentation.getSlides().get_Item(0)
    smile = slide.getShapes().addAutoShape(ShapeType.SmileyFace, 110, 20, 500, 500)
    sequence = slide.getTimeline().getMainSequence()
    effect = sequence.addEffect(smile, EffectType.Fly, EffectSubtype.TopLeft, EffectTriggerType.AfterPrevious)
    effect.getTiming().setDuration(2.0)

    generator = PresentationAnimationsGenerator(presentation)
    try:
        callback = jpype.JProxy("com.aspose.slides.PresentationAnimationsGenerator$NewAnimation", dict(invoke=save_animation_states))
        generator.setNewAnimation(callback)
        generator.run(presentation.getSlides())
    finally:
        generator.dispose()
finally:
    presentation.dispose()

サポートされているアニメーションとエフェクト

以下の表は、Java 変換記事で説明されているレンダリングサポートをまとめたものです。プレゼンテーションが未サポートのエフェクトを使用している場合は、生成されたフレームをプレビューしてください。

入口:

アニメーションの種類 Aspose.Slides PowerPoint
Appear No Yes
Fade Yes Yes
Fly In Yes Yes
Float In Yes Yes
Split Yes Yes
Wipe Yes Yes
Shape Yes Yes
Wheel Yes Yes
Random Bars Yes Yes
Grow & Turn No Yes
Zoom Yes Yes
Swivel Yes Yes
Bounce Yes Yes

強調:

アニメーションの種類 Aspose.Slides PowerPoint
Pulse No Yes
Color Pulse No Yes
Teeter Yes Yes
Spin Yes Yes
Grow/Shrink No Yes
Desaturate No Yes
Darken No Yes
Lighten No Yes
Transparency No Yes
Object Color No Yes
Complementary Color No Yes
Line Color No Yes
Fill Color No Yes

退出:

アニメーションの種類 Aspose.Slides PowerPoint
Disappear No Yes
Fade Yes Yes
Fly Out Yes Yes
Float Out Yes Yes
Split Yes Yes
Wipe Yes Yes
Shape Yes Yes
Random Bars Yes Yes
Shrink & Turn No Yes
Zoom Yes Yes
Swivel Yes Yes
Bounce Yes Yes

モーション パス::

アニメーションの種類 Aspose.Slides PowerPoint
Lines Yes Yes
Arcs Yes Yes
Turns Yes Yes
Shapes Yes Yes
Loops Yes Yes
Custom Path Yes Yes

よくある質問

Aspose.Slides は直接 MP4 ファイルを作成しますか?

いいえ。Aspose.Slides はプレゼンテーションのフレームを生成します。FFmpeg などのビデオエンコーダーを使用してそれらを MP4 ファイルに結合してください。

動画の再生が期待より速くまたは遅くなるのはなぜですか?

フレーム生成時とエンコーダの入力フレームレートで同じ FPS を使用してください。不一致があると画像シーケンスの再生時間が変わります。

パスワードで保護されたプレゼンテーションを変換できますか?

はい。保護されたプレゼンテーションの読み込み 時に正しいパスワードを指定し、ロードされたコンテンツからフレームを生成してください。

このワークフローはプレゼンテーションの音声を保持しますか?

サンプルは画像フレームのみをエクスポートするため、生成された動画は無音です。音声を含めるには、動画エンコード時に別途音声トラックを提供してください。

一時的なディスク使用量を減らすにはどうすればよいですか?

フレームサイズを小さくするか、FPS を下げてください。また、エンコードが成功したら一時的な PNG ファイルを削除します。設定を減らす際は、結果の動画品質を確認してください。