Convertir presentaciones de PowerPoint a video en Python
Descripción general
Convertir una presentación de PowerPoint o OpenDocument a video permite a los espectadores ver su contenido en un reproductor de video sin abrir una aplicación de presentaciones. Aspose.Slides for Python via Java representa las animaciones y transiciones de la presentación en fotogramas de imagen. Un codificador separado, como FFmpeg, combina esos fotogramas en un archivo de video.
Note
Prueba el convertidor en línea de PowerPoint a Video para ver la conversión de presentación a video en acción.Convertir PowerPoint a video
La conversión consta de dos etapas: generar fotogramas PNG a una velocidad de fotogramas elegida y, a continuación, codificar la secuencia de imágenes como MP4. Utiliza la misma velocidad de fotogramas en ambas etapas para preservar la sincronización de la animación.
Antes de ejecutar el ejemplo:
- Configura Aspose.Slides for Python via Java.
- Descarga FFmpeg y haz que su ejecutable esté disponible en
PATH. El ejemplo utiliza una compilación con el codificadorlibx264. - Ejecuta el siguiente código Python en un directorio con permisos de escritura.
El ejemplo crea una forma sonriente con animaciones de entrada y salida, genera fotogramas a 30 FPS y llama a FFmpeg para crear output.mp4. Un directorio de fotogramas nuevo evita que los fotogramas de ejecuciones anteriores se incluyan en el 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}.")
Para convertir un archivo existente, inicializa Presentation con su ruta y omite las sentencias de creación de forma y de animación.
El comando FFmpeg lee una secuencia de imágenes numerada, rellena las dimensiones impares a valores pares y escribe video H.264 con el formato de píxeles yuv420p. La opción -n evita sobrescribir un archivo de salida existente. Los archivos PNG generados permanecen en el directorio de fotogramas; elimínalos cuando ya no sean necesarios.
Note
Este ejemplo codifica solo fotogramas de imagen. No añade narración ni audio incrustado de la presentación al video de salida.Efectos de video
Las animaciones controlan cómo aparecen, se mueven o desaparecen los objetos de la diapositiva. Las transiciones controlan el paso entre diapositivas. Añade estos efectos antes de generar los fotogramas de video.
Consulta Animación de PowerPoint, Animación de formas, Efectos de formas, y Transiciones de diapositivas.
Añadir una transición de diapositiva
El siguiente ejemplo independiente crea una presentación con dos diapositivas. La segunda diapositiva tiene un fondo magenta y una transición de empuje. Guarda la presentación y luego utilízala como entrada para el ejemplo de generación de fotogramas anterior.
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()
Animar párrafos
El texto puede aparecer párrafo a párrafo. Este ejemplo crea tres párrafos con efectos de entrada de fundido secuencial, cada uno retrasado un segundo después del efecto anterior. Utiliza el archivo guardado paragraphs.pptx como entrada para el ejemplo de conversión de video.
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()
Clases de conversión de video
PresentationAnimationsGenerator genera eventos de animación para las diapositivas. Construirlo a partir de una presentación utiliza el tamaño de diapositiva de la presentación para los fotogramas. Utiliza setDefaultDelay para configurar el retardo predeterminado en milisegundos.
PresentationPlayer muestrea las animaciones generadas a la velocidad de fotogramas suministrada a su constructor. Registra una devolución de llamada de Python a través de JPype con setFrameTick, luego llama a run para generar los fotogramas. El primer ejemplo utiliza su propio contador basado en cero para que los nombres de archivo coincidan con la secuencia de entrada de FFmpeg.
Para estados de animación individuales, registra una devolución de llamada con setNewAnimation. La devolución de llamada recibe un reproductor de animación que puede posicionarse en un tiempo seleccionado. El siguiente ejemplo guarda los primeros y últimos fotogramas de cada animación generada con nombres de archivo únicos:
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()
Animaciones y efectos compatibles
Las siguientes tablas resumen la compatibilidad de renderizado descrita en el artículo de conversión de Java. Visualiza una vista previa de los fotogramas generados cuando una presentación utiliza efectos que no son compatibles.
Entrada:
| Tipo de animación | Aspose.Slides | PowerPoint |
|---|---|---|
| Aparecer | No | Sí |
| Desvanecer | Sí | Sí |
| Entrar volando | Sí | Sí |
| Entrar flotando | Sí | Sí |
| Dividir | Sí | Sí |
| Barrer | Sí | Sí |
| Forma | Sí | Sí |
| Rueda | Sí | Sí |
| Barras aleatorias | Sí | Sí |
| Crecer y girar | No | Sí |
| Zoom | Sí | Sí |
| Giro | Sí | Sí |
| Rebotar | Sí | Sí |
Énfasis:
| Tipo de animación | Aspose.Slides | PowerPoint |
|---|---|---|
| Pulso | No | Sí |
| Pulso de color | No | Sí |
| Balanceo | Sí | Sí |
| Giro | Sí | Sí |
| Crecer/Encoger | No | Sí |
| Desaturar | No | Sí |
| Oscurecer | No | Sí |
| Aclarar | No | Sí |
| Transparencia | No | Sí |
| Color del objeto | No | Sí |
| Color complementario | No | Sí |
| Color de línea | No | Sí |
| Color de relleno | No | Sí |
Salida:
| Tipo de animación | Aspose.Slides | PowerPoint |
|---|---|---|
| Desaparecer | No | Sí |
| Desvanecer | Sí | Sí |
| Salir volando | Sí | Sí |
| Salir flotando | Sí | Sí |
| Dividir | Sí | Sí |
| Barrer | Sí | Sí |
| Forma | Sí | Sí |
| Barras aleatorias | Sí | Sí |
| Encoger y girar | No | Sí |
| Zoom | Sí | Sí |
| Giro | Sí | Sí |
| Rebotar | Sí | Sí |
Rutas de movimiento:
| Tipo de animación | Aspose.Slides | PowerPoint |
|---|---|---|
| Líneas | Sí | Sí |
| Arcos | Sí | Sí |
| Giros | Sí | Sí |
| Formas | Sí | Sí |
| Bucles | Sí | Sí |
| Ruta personalizada | Sí | Sí |
Preguntas frecuentes
¿Aspose.Slides crea un archivo MP4 directamente?
No. Aspose.Slides genera fotogramas de la presentación. Utiliza un codificador de video como FFmpeg para combinarlos en un archivo MP4.
¿Por qué el video se reproduce más rápido o más lento de lo esperado?
Utiliza la misma velocidad de fotogramas (FPS) para la generación de fotogramas y la velocidad de fotogramas de entrada del codificador. Una discrepancia altera la duración de reproducción de la secuencia de imágenes.
¿Puedo convertir una presentación protegida con contraseña?
Sí. Proporciona la contraseña correcta al cargar la presentación protegida, y luego genera los fotogramas del contenido cargado.
¿Este flujo de trabajo preserva el audio de la presentación?
Los ejemplos exportan fotogramas de imagen, por lo que el video resultante es silencioso. Para incluir audio, proporciona una pista de audio por separado durante la codificación del video.
¿Cómo puedo reducir el uso temporal del disco?
Utiliza un tamaño de fotograma más pequeño o una FPS más baja, y elimina los archivos PNG temporales tras una codificación exitosa. Verifica la calidad del video resultante al reducir cualquiera de los ajustes.