Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

How can I copy slide?

I created a template slide and I need to copy it and edit shapes of each copy separately.

Or how I can add my template slide to presentation.slide_layouts?

This is what I found on GitHub, and it works for me. I did change a couple of things for my project. You will need to import six and copy. I am using pptx-6.10

def duplicate_slide(pres, index):
    template = pres.slides[index]
        blank_slide_layout = pres.slide_layouts[12]
    except:
        blank_slide_layout = pres.slide_layouts[len(pres.slide_layouts)]
    copied_slide = pres.slides.add_slide(blank_slide_layout)
    for shp in template.shapes:
        el = shp.element
        newel = copy.deepcopy(el)
        copied_slide.shapes._spTree.insert_element_before(newel, 'p:extLst')
    for _, value in six.iteritems(template.part.rels):
        # Make sure we don't copy a notesSlide relation as that won't exist
        if "notesSlide" not in value.reltype:
            copied_slide.part.rels.add_relationship(
                value.reltype,
                value._target,
                value.rId
    return copied_slide

Then you can create the copy with passing in your presentation and the slide index of your template:

copied_slide = duplicate_slide(pres, 4)

I am still working on editing the shapes from the copied slide, once I am further along in my project I can update

I wanted to present my workaround to copy slides. I use a template ppt and populate it. I know before populating the slides which slides of the template need to be copied and how often. What I then do is copying the slides and saving the new ppt with the copied slides. After saving I can open the ppt with the copied slides and use pptx to populate the slides.

import win32com.client
ppt_instance = win32com.client.Dispatch('PowerPoint.Application')
#open the powerpoint presentation headless in background
read_only = True
has_title = False
window    = False
prs = ppt_instance.Presentations.open('path/ppt.pptx',read_only,has_title,window)
nr_slide = 1
insert_index = 1
prs.Slides(nr_slide).Copy()
prs.Slides.Paste(Index=insert_index)
prs.SaveAs('path/new_ppt.pptx')
prs.Close()
#kills ppt_instance
ppt_instance.Quit()
del ppt_instance

In this case the firste slide would be copied of the presentation and inserted after the first slide of the same presentation.

Hope this helps some of you!

This is a very interesting approach, thanks for adding this to this thread. I have been looking for a good way to copy slides using python-pptx, but this does the job much better. – MalteHerrmann Nov 18, 2019 at 8:52

Since I also found another usecase for the code shared by @d_bergeron, I just wanted to share it here. In my case, I wanted to copy a slide from another presentation into the one I generated with python-pptx:

As argument I pass in the Presentation() object I created using python-pptx (prs = Presenation()).

from pptx import Presentation
import copy
def copy_slide_from_external_prs(prs):
    # copy from external presentation all objects into the existing presentation
    external_pres = Presentation("PATH/TO/PRES/TO/IMPORT/from.pptx")
    # specify the slide you want to copy the contents from
    ext_slide = external_pres.slides[0]
    # Define the layout you want to use from your generated pptx
    SLD_LAYOUT = 5
    slide_layout = prs.slide_layouts[SLD_LAYOUT]
    # create now slide, to copy contents to 
    curr_slide = prs.slides.add_slide(slide_layout)
    # now copy contents from external slide, but do not copy slide properties
    # e.g. slide layouts, etc., because these would produce errors, as diplicate
    # entries might be generated
    for shp in ext_slide.shapes:
        el = shp.element
        newel = copy.deepcopy(el)
        curr_slide.shapes._spTree.insert_element_before(newel, 'p:extLst')
    return prs

I am mainly posting it here, since I was looking for a way to copy an external slide into my presentation and ended up in this thread.

I edited @n00by0815 solution and came up with very elegant code, which also can copy images without errors:

# ATTENTNION: PPTX PACKAGE RUNS ONLY ON CERTAINS VERSION OF PYTHON (https://python-pptx.readthedocs.io/en/latest/user/install.html)
from pptx import Presentation
from pptx.util import Pt
from pptx.enum.text import PP_ALIGN
import copy
import os
DIR_PATH = os.path.dirname(os.path.realpath(__file__))
#modeled on https://stackoverflow.com/a/56074651/20159015 and https://stackoverflow.com/a/62921848/20159015
#this for some reason doesnt copy text properties (font size, alignment etc.)
def SlideCopyFromPasteInto(copyFromPres, slideIndex,  pasteIntoPres):
    # specify the slide you want to copy the contents from
    slide_to_copy = copyFromPres.slides[slideIndex]
    # Define the layout you want to use from your generated pptx
    slide_layout = pasteIntoPres.slide_layouts.get_by_name("Blank") # names of layouts can be found here under step 3: https://www.geeksforgeeks.org/how-to-change-slide-layout-in-ms-powerpoint/
    # it is important for slide_layout to be blank since you dont want these "Write your title here" or something like that textboxes
    # alternative: slide_layout = pasteIntoPres.slide_layouts[copyFromPres.slide_layouts.index(slide_to_copy.slide_layout)]
    # create now slide, to copy contents to 
    new_slide = pasteIntoPres.slides.add_slide(slide_layout)
    # create images dict
    imgDict = {}
    # now copy contents from external slide, but do not copy slide properties
    # e.g. slide layouts, etc., because these would produce errors, as diplicate
    # entries might be generated
    for shp in slide_to_copy.shapes:
        if 'Picture' in shp.name:
            # save image
            with open(shp.name+'.jpg', 'wb') as f:
                f.write(shp.image.blob)
            # add image to dict
            imgDict[shp.name+'.jpg'] = [shp.left, shp.top, shp.width, shp.height]
        else:
            # create copy of elem
            el = shp.element
            newel = copy.deepcopy(el)
            # add elem to shape tree
            new_slide.shapes._spTree.insert_element_before(newel, 'p:extLst')
    # things added first will be covered by things added last => since I want pictures to be in foreground, I will add them after others elements
    # you can change this if you want
    # add pictures
    for k, v in imgDict.items():
        new_slide.shapes.add_picture(k, v[0], v[1], v[2], v[3])
        os.remove(k)
    return new_slide # this returns slide so you can instantly work with it when it is pasted in presentation
templatePres = Presentation(f"{DIR_PATH}/template.pptx")
outputPres = Presentation() 
outputPres.slide_height, outputPres.slide_width = templatePres.slide_height, templatePres.slide_width
# this can sometimes cause problems. Alternative:
# outputPres = Presentation(f"{DIR_PATH}/template.pptx") and now delete all slides to have empty presentation
# if you just want to copy and paste slide:
SlideCopyFromPasteInto(templatePres,0,outputPres)
# if you want to edit slide that was just pasted in presentation:
pastedSlide = SlideCopyFromPasteInto(templatePres,0,outputPres)
pastedSlide.shapes.title.text = "My very cool title"
for shape in pastedSlide.shapes:
    if not(shape.has_text_frame): continue
    # easiest ways to edit text fields is to put some identifying text in them
    if shape.text_frame.text == "personName": # there is a text field with "personName" written into it
        shape.text_frame.text = "Brian"
    if shape.text_frame.text == "personSalary":
        shape.text_frame.text = str(brianSalary)
    # stylizing text need to be done after you change it
    shape.text_frame.paragraphs[0].font.size = Pt(80) 
    shape.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
outputPres.save(f'{DIR_PATH}/output.pptx')
                Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
– Community
                Oct 7, 2022 at 22:37
                I tried to use this with slides generated from SSRS.  Those slides have one image of all of the content but the pictures do not have a name.  May I suggest checking for the image attribute instead of checking for picture in the name?  if hasattr(shp, 'image'): and then I changed the image name saved to file to include a variable which increments each loop.
– jimmiesrustled
                Oct 12, 2022 at 18:09

Here is another way to copy each slide onto a single PPTX slide for an entire presentation, and then you can use LibreOffice to convert each individual powerpoint into an image:

def get_slide_count(prs):
""" Get the number of slides in PPTX presentation """
    slidecount = 0
    for slide in prs.slides:
        slidecount += 1
    return slidecount
def delete_slide(prs, slide):
    """ Delete a slide out of a powerpoint presentation"""
    id_dict = { slide.id: [i, slide.rId] for i,slide in enumerate(prs.slides._sldIdLst) }
    slide_id = slide.slide_id
    prs.part.drop_rel(id_dict[slide_id][1])
    del prs.slides._sldIdLst[id_dict[slide_id][0]]
def get_single_slide_pres(prs, slidetokeep):
    for idx, slide in enumerate(prs.slides):
        if idx < slidetokeep:
            delete_slide(prs, slide)
        elif (idx > slidetokeep):
            delete_slide(prs, slide)
    prs.save(str(slidetokeep + 1) + ".pptx")
pptxfilepath = "test.pptx"
prs = Presentation(pptxfilepath)
slidecount = get_slide_count(prs)
for i in range(slidecount):
    prs_backup = Presentation(pptxfilepath)
    get_single_slide_pres(prs_backup, i)
    prs_backup = None

Sorry for the delay, I was moved to another project. I was able to complete my ppt project using multiple template slides and copying them. At the end of building the presentation I delete the templates. To grab the shapes you will need to iterate through the slide.shapes and find the name of the shape that you are looking for. Once you have this returned you can then edit the shape as needed. I have added a version of the add_text function that I use to populate shape.text_frame.

def find_shape_by_name(shapes, name):
    for shape in shapes:
        if shape.name == name:
            return shape
    return None
def add_text(shape, text, alignment=None):
    if alignment:
        shape.vertical_anchor = alignment
    tf = shape.text_frame
    tf.clear()
    run = tf.paragraphs[0].add_run()
    run.text = text if text else ''

To find the shape "slide_title".

slide_title = find_shape_by_name(slide.shapes,'slide_title')

To add text to the shape.

add_text(slide_title,'TEST SLIDE')

Please let me know if you need any other assistance.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.