Convert PowerPoint Presentations to Video in Python

Overview

Converting a PowerPoint or OpenDocument presentation to video lets viewers watch its content in a video player without opening a presentation application. Aspose.Slides for Python via Java renders presentation animations and transitions into image frames. A separate encoder, such as FFmpeg, combines those frames into a video file.

Convert PowerPoint to Video

The conversion has two stages: generate PNG frames at a chosen frame rate, then encode the image sequence as MP4. Use the same frame rate in both stages to preserve animation timing.

Before running the example:

  1. Set up Aspose.Slides for Python via Java.
  2. Download FFmpeg and make its executable available on PATH. The example uses a build with the libx264 encoder.
  3. Run the following Python code in a writable directory.

The example creates a smiling shape with entrance and exit animations, renders frames at 30 FPS, and calls FFmpeg to create output.mp4. A fresh frame directory prevents frames from earlier runs from being included in the video.

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}.")

To convert an existing file, initialize Presentation with its path and omit the shape-creation and animation-creation statements.

The FFmpeg command reads a numbered image sequence, pads odd dimensions to even values, and writes H.264 video with the yuv420p pixel format. The -n option prevents overwriting an existing output file. Generated PNG files remain in the frame directory; remove them when they are no longer needed.

Video Effects

Animations control how slide objects appear, move, or disappear. Transitions control the change between slides. Add these effects before generating video frames.

See PowerPoint Animation, Shape Animation, Shape Effects, and Slide Transitions.

Add a Slide Transition

The following self-contained example creates a presentation with two slides. The second slide has a magenta background and a push transition. Save the presentation, then use it as the input to the frame-generation example above.

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()

Animate Paragraphs

Text can appear paragraph by paragraph. This example creates three paragraphs with sequential fade entrance effects, each delayed by one second after the previous effect. Use the saved paragraphs.pptx file as the input to the video-conversion example.

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()

Video Conversion Classes

PresentationAnimationsGenerator generates animation events for the slides. Constructing it from a presentation uses the presentation’s slide size for the frames. Use setDefaultDelay to configure the default delay in milliseconds.

PresentationPlayer samples the generated animations at the frame rate supplied to its constructor. Register a Python callback through JPype with setFrameTick, then call run to generate the frames. The first example uses its own zero-based counter so the filenames match FFmpeg’s input sequence.

For individual animation states, register a callback with setNewAnimation. The callback receives an animation player that can be positioned at a selected time. The following example saves the first and last frames of each generated animation with unique filenames:

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()

Supported Animations and Effects

The following tables summarize the rendering support described in the Java conversion article. Preview the generated frames when a presentation uses effects that are not supported.

Entrance:

Animation Type 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

Emphasis:

Animation Type 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

Exit:

Animation Type 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

Motion Paths:

Animation Type Aspose.Slides PowerPoint
Lines Yes Yes
Arcs Yes Yes
Turns Yes Yes
Shapes Yes Yes
Loops Yes Yes
Custom Path Yes Yes

FAQ

Does Aspose.Slides create an MP4 file directly?

No. Aspose.Slides generates presentation frames. Use a video encoder such as FFmpeg to combine them into an MP4 file.

Why does the video play faster or slower than expected?

Use the same FPS for frame generation and the encoder’s input frame rate. A mismatch changes the playback duration of the image sequence.

Can I convert a password-protected presentation?

Yes. Supply the correct password when loading the protected presentation, then generate frames from the loaded content.

Does this workflow preserve presentation audio?

The examples export image frames, so the resulting video is silent. To include audio, provide an audio track separately during video encoding.

How can I reduce temporary disk usage?

Use a smaller frame size or a lower FPS, and remove temporary PNG files after successful encoding. Check the resulting video quality when reducing either setting.