Search code examples
python-pptx

How to detect all existing PNG/JPG images in pptx slide and then manipulate their size/layout using python pptx?


I have a PowerPoint presentation with dozens of slides in Title only format but with image objects. The objects are usually (1) a big graph image, (2) one small legend image, and (3) another small legend image. The images are usually oversized, exceeding the slide dimensions or overlapping each other. I want to clean up the slide images using the following steps:

  1. Open an existing pptx with known filename (already know how to do this)
  2. Start at Slide 2
  3. Find all images in slide. Determine which is the leftmost image. (I got stuck here.)
  4. The image at the leftmost is the (1) graph image. Adjust this until it reaches height of either 6.4" or width of 13". Align this to leftmost edge and topmost edge (touching the slide title textbox)
  5. If the graph image is 6.4" height, move the legend images adjacent to the right edge of the graph image. Align their top edges.
  6. If the graph image is 13" width, move the legend images adjacent to the bottom edge of the graph image. Align their right edges.
  7. Repeat until last slide
  8. Skip slides with section header layout.

Update: Here's my code so far

from pptx import Presentation
import glob
from pptx.util import Inches
from pptx.enum.text import PP_ALIGN

f = open('C:\\Users\\7188712\\Desktop\\Script Validation\\XTI\\Blade2T_XTI (Tag1.7.1.40).pptx', 'rb')
prs = Presentation(f)
slides = prs.slides
for slide in prs.slides:
    print('\nslide number ', slides.index(slide)+1, slide.shapes.title.text)
    for shape in slide.shapes:
        #if shape.shape_type == 13:  #Type 13 means PICTURE type
            #print("id: %s, height: %s, width: %s, ext: %s"% \
             #     (shape.shape_id, round(shape.height.inches,2), round(shape.width.inches,2), shape.image.ext)) 
         print('id: %s, height: %s, width: %s'% \
                (shape.shape_id, round(shape.height.inches,2), round(shape.width.inches,2)), shape.shape_type, shape.name) 

         if shape.name == 'Title 1':
            shape.alignment = PP_ALIGN.LEFT     


    

Solution

  • Finally!

    from pptx import Presentation
    import glob
    from pptx.util import Inches, Emu, Pt
    from pptx.enum.text import PP_ALIGN
    
    #Initialize variables
    pic_start = 7           #Slide page where JMP graphs start
    space_ht = Inches(6.3)  #Space for images height
    space_wt = Inches(13)   #Space for images width
    path = 'C:\\Users\\Name\\Desktop\Folder\\'
    fname = 'filename'
    
    #Open pptx
    f = open(path+fname, 'rb')
    prs = Presentation(f)
    slides = prs.slides
    
    #Scan each slide
    for slide in prs.slides:
        print('\nslide number ', slides.index(slide)+1, slide.shapes.title.text)
        for shape in slide.shapes:
    
            #Show all objects in the slide
            print('id: %s, height: %s, width: %s, left: %s'%(shape.shape_id, round(shape.height.inches,2), round(shape.width.inches,2), \
                    round(shape.left.inches,2)), shape.shape_type, shape.name) 
    
            #Modify slide sections to section header-like format
            if shape.shape_type == 17 and shape.text == '<change layout for title slide>':  #Type 17 means TEXT_BOX type 
                shape.text = ''
                slide.shapes[0].width = Inches(11.5)
                slide.shapes[0].height = Inches(3.12)
                slide.shapes[0].left = Inches(0.91)
                slide.shapes[0].top = Inches(1.87)
                slide.shapes[0].text_frame.fit_text(font_family=u'Verdana', max_size=60, bold=True)
    
            #Modify slide titles starting page 2
            if shape.shape_type == 14 and slides.index(slide) != 0: #Type 14 means PLACEHOLDER type and we don't edit the title page
                if shape.text == slide.shapes.title.text:   #check if this is the title
                    shape.height = Inches(0.52)
                    shape.text_frame.paragraphs[0].alignment = PP_ALIGN.LEFT
                    shape.text_frame.fit_text(font_family=u'Verdana', max_size=24, bold=True)
                    shape.left = Inches(0.2)
                    top_margin = shape.height.inches
                          
            #Modify pages starting picstart for picture
            if shape.shape_type == 13 and slides.index(slide) > pic_start-2 and slide.shapes.title.text != 'Legends': #Type 13 means PICTURE type
                shape.left = Inches(0.2)
                shape.top = Inches(top_margin)
                pic_ratio = shape.width/shape.height
                space_ratio = space_wt/space_ht
    
                #Adjust length and with to fit slide
                if pic_ratio > space_ratio:
                    shape.width = Emu(space_wt)
                    shape.height = Emu(space_wt/pic_ratio)
                else:
                    shape.height = Emu(space_ht)
                    shape.width = Emu(space_ht*pic_ratio)
                
    #Save and close
    f.close()
    prs.save(path+fname)