Python Office Automation with PPT — How to use python-pptx part2

1. Introduction
The previous article briefly introduced the document structure of PPT and used the python-pptx dependency library to perform the most basic operations on PPT documents. As the second article in the PPT series, this piece will cover the following content:

  • Tables
  • Images (including static images and GIF animated images)
  • Videos

2. Tables
After instantiating a Slide object, you can use the following method to insert a table:

Methodslide.shapes.add_table(rows, cols, left, top, width, height)

Parameters:

  • rows: Number of table rows
  • cols: Number of table columns
  • left: Left margin
  • top: Top margin
  • width: Table width
  • height: Table height

Return typepptx.shapes.graphfrm.GraphicFrame
Its table property is a table object: pptx.table.Table

python

def insert_table(slide, rows, cols, left, top, width, height, unit=Cm):
    """
    Insert a table into a slide
    :param unit: Default unit is centimeters
    :param slide: Slide object
    :param rows: Number of rows
    :param cols: Number of columns
    :param left: Left margin
    :param top: Top margin
    :param width: Width
    :param height: Height
    :return:
    """
    # Insert a table
    table = slide.shapes.add_table(rows, cols, unit(left), unit(top), unit(width), unit(height))

    # Return table object
    return table.table

# 1. Create a Slide object (blank style)
slide = add_slide(self.presentation, 6)

# 2. Insert a table
# Parameters: slide object, rows, columns, left margin, top margin, width, height
table = insert_table(slide, 3, 3, 3, 5, 13.6, 5)

2.1 Adjusting Row Height and Column Width
For aesthetic table generation, adjusting row height and column width is necessary. The table object’s columns and rows properties are used to get all column and row objects respectively.

python

def set_table_column_width(table, column_index, width, unit=Cm):
    """
    Set width of a specific column in table
    :param table:
    :param column_index:
    :param width:
    :param unit: Unit defaults to centimeters
    :return:
    """
    table.columns[column_index].width = unit(width)

def set_table_row_height(table, row_index, height, unit=Cm):
    """
    Set height of a specific row in table
    :param table:
    :param row_index:
    :param height:
    :param unit:
    :return:
    """
    table.rows[row_index].height = unit(height)

# 3. Reset table width and height
# 3.1 Set column widths for columns 1-3
set_table_column_width(table, 0, 5)
set_table_column_width(table, 1, 5)
set_table_column_width(table, 2, 5)

# 3.2 Set row heights
set_table_row_height(table, 0, 1.5)
set_table_row_height(table, 1, 1.2)
set_table_row_height(table, 2, 1.2)

2.2 Setting Cell Data
First, get the corresponding cell object using row and column indices:

python

# Get a specific cell object
# Note: Index starts from 0
# Example: Get cell object at first row, first column
cell = table.cell(0, 0)

Then, set the cell object’s text property to the specified content:

python

# Set cell value
cell.text = "Content displayed in cell"

This way, we can define a set of data and insert it into the table:

python

# 4. Set table data
datas = [
    ["Student", "Name", "Age"],
    ["", "Xing An Guo", 23],
    ["", "AirPython", 18]]

# Iterate and set data into cells
for row_index in range(len(table.rows)):
    for column_index in range(len(table.columns)):
        # Get cell object
        cell_temp = table.cell(row_index, column_index)

        # Set data
        cell_temp.text = str(datas[row_index][column_index])

2.3 Cell Style Adjustment
Adjusting cell styles involves these 3 steps:

  1. Get the cell text object
  2. Get the paragraph object of the text object
  3. Specify paragraph alignment and text style through the paragraph

Example: Set first row header cell text to bold and center-aligned:

python

# 5. Set first row header cell text to bold and center-aligned
for column_index in range(len(table.columns)):
    # 1. Cell object
    cell = table.cell(0, column_index)
    # 2. Paragraph of text control
    paragraph = cell.text_frame.paragraphs[0]
    # 3. Set paragraph style
    set_parg_font_style(paragraph, font_name='Microsoft YaHei', font_size=23, font_color=[255, 0, 0],
                        font_bold=True)

Note: Besides using the default paragraph, text controls in cells can also add new paragraphs with different content and styles.

2.4 Cell Background Color
The method for setting text box background color from the previous article also applies to cells:

python

def set_widget_bg(widget, bg_rgb_color=None):
    """
    Set background color for [textbox/cell/shape]
    :param widget: Textbox, cell, shape
    :param bg_rgb_color: Background color value
    :return:
    """
    if bg_rgb_color and len(bg_rgb_color) == 3:
        # 1. Set shape fill type to solid
        widget.fill.solid()
        # 2. Set background color
        widget.fill.fore_color.rgb = RGBColor(bg_rgb_color[0], bg_rgb_color[1], bg_rgb_color[2])

# Set cell background color
set_widget_bg(cell, [204, 217, 225])

2.5 Merging Cells
Syntax:

python

# Merge cells
start_cell.merge(end_cell)

Example: Merge cells and center-align the content:

python

from pptx.enum.text import MSO_VERTICAL_ANCHOR, MSO_ANCHOR

def set_cell_center(cell):
    """
    Set cell text to center alignment
    :param cell:
    :return:
    """
    paragraph = cell.text_frame.paragraphs[0]
    paragraph.alignment = PP_ALIGN.CENTER
    cell.vertical_anchor = MSO_ANCHOR.MIDDLE

# 6. Cell merging
# Merge cells and center-align display
table.cell(1, 0).merge(table.cell(2, 0))
table.cell(1, 0).text = "Merged"
set_cell_center(table.cell(1, 0))

3. Images
Both static images and GIF animated images are inserted into slides in the same way.

Methodslide.shapes.add_picture(image_file, left, top, width, height)

Parameters:

  • image_file: Image path
  • left: Left margin
  • top: Top margin
  • width: Image display width
  • height: Image display height

python

def insert_image(slide, pic_path, left, top, width=None, height=None, unit=Inches):
    """
    Add image to slide (including static and animated images)
    :param unit: Unit defaults to Inches
    :param pic_path: File path
    :param slide: Slide object
    :param left: Left margin
    :param top: Top margin
    :param width: Width
    :param height: Height
    :return:
    """
    # Note: If both width and height are None, display with original image size
    width = unit(width) if width else None
    height = unit(height) if height else None

    pic_obj = slide.shapes.add_picture(image_file=pic_path,
                                       left=unit(left),
                                       top=unit(top),
                                       width=width,
                                       height=height)
    return pic_obj

def image_manage(self):
    """
    Image management
    :return:
    """
    # Insert a static image
    slide = add_slide(self.presentation, 6)

    # Image path
    image_path = './1.jpeg'

    # Insert local image
    insert_image(slide, image_path, 6, 6, unit=Cm)

Note: When width and height are not explicitly specified (default None), the image displays at its actual size. When the image is very large, it may not display completely.

Therefore, in actual projects, we should first get the image’s aspect ratio, then set width and height parameters proportionally:

python

from PIL import Image

def get_image_aspect_ratio(image_path):
    """
    Get image aspect ratio
    :param image_path:
    :return:
    """
    img = Image.open(image_path)

    # Image type: GIF
    image_format = img.format

    # Image width, height
    width, height = img.size

    # Image aspect ratio
    aspect_ratio = width / height

    return aspect_ratio

# Get width/height ratio
aspect_ratio = get_image_aspect_ratio(image_path)

# Insert image into PPT proportionally
insert_image(slide, image_path, 6, 6, 6, 6 / aspect_ratio, unit=Cm)

4. Videos
The method for inserting videos into PPT documents is:

python

slide.shapes.add_movie(video_path, left, top, width, height, poster_frame_image)

Parameters:

  • video_path: Video path
  • left: Left margin
  • top: Top margin
  • width: Video display width
  • height: Video display height
  • poster_frame_image: Video thumbnail path

4.1 Getting Video Aspect Ratio
To ensure videos display completely in PPT, we need to first get the video’s width/height ratio. It’s recommended to install the moviepy dependency library to get video basic information:

python

# Install dependency
pip3 install moviepy

Then, create a VideoFileClip object and get the video’s width and height from it:

python

from moviepy.editor import VideoFileClip

def get_video_aspect_ratio_and_thumbnail_path(video_path, frame_index):
    """
    Get video width/height ratio
    :param video_path: Video path
    :param frame_index: Frame index
    :return:
    """
    clip = VideoFileClip(video_path)

    # Video width, height
    width, height = clip.size

    # Get width/height ratio
    aspect_ratio = width / height

4.2 Getting Video Frames
For video thumbnails, we can select a frame from the video and save it locally:

python

def get_video_frame(clip, frame_index):
    """
    Get a specific frame from video
    :param clip:
    :param frame_index:
    :return:
    """
    # Number of frames
    frame_count = math.floor(clip.fps * clip.duration)
    # print('Number of video frames:', frame_count)

    # Ensure parameter input is valid
    if frame_index < 0 or frame_index > frame_count:
        frame_index = 1

    # All video frames
    frames = clip.iter_frames()
    # clip.get_frame()

    # Define output image path
    thumbnail_path = "{}/temp/{}.jpg".format(os.path.abspath(os.path.dirname(__file__)), random_str(10))

    # Iterate to find corresponding frame, save locally
    for index, frame in enumerate(frames):
        if frame_index == index:
            # Save frame image locally
            im = Image.fromarray(frame)
            im.save(thumbnail_path)
            break

    return thumbnail_path

4.3 Inserting Videos
Finally, encapsulate the video insertion operation. Pass in the video thumbnail, left margin, top margin, and display width to complete video insertion:

python

def insert_video(self):
    """
    Insert video
    :return:
    """
    slide = add_slide(self.presentation, 6)

    video_path = './1.mp4'

    # Get image aspect ratio and save a temporary thumbnail locally
    aspect_ratio, thumbnail_path = get_video_aspect_ratio_and_thumbnail_path(video_path, 120)

    # Insert video into PPT
    insert_video(slide, video_path, thumbnail_path, 3, 3, 4, 4 / aspect_ratio)

# Insert video into PPT
insert_video(slide, video_path, thumbnail_path, 3, 3, 4, 4 / aspect_ratio)

5. Conclusion
This article covered operations for three common types of content in PPT documents: tables, images, and videos.