Tuck
Tuck

Reputation: 203

Picture Insert in python-pptx Fails With Error: LayoutPlaceholder has no attribute insert_picture

Although I can generate a presentation, populate text placeholders without issue and successfully save the generated presentation I am consistently getting an error when trying to populate a picture placeholder. I have confirmed that I am working with the correct placeholder object and that it is a picture placeholder (type 18). I have written the code to follow the examples from the online docs and, at this point, cannot figure out why I'm getting this error:

AttributeError: 'LayoutPlaceholder' object has no attribute 'insert_picture'

This is the section of code being executed, which throws the error after executing the last line:

# Bring in a new slide from layout and add to deck
objContentSlide = objPrs.slide_layouts[1]
objPrs.slides.add_slide(objContentSlide)

# Collect the placeholders
objContentShapes = objContentSlide.placeholders

# Populate title placeholder (text)
objContentSlideTitle = list(filter(lambda x: x.name == "slide1Title",objContentShapes))[0]
objContentSlideTitle.text = CNSDETAILSLIDETITLEPREFIX + strMonthName + CNSDETAILSLIDETITLESUFFIX

# Populate forecast placeholder (text)
objContentSlideForecast = list(filter(lambda x: x.name == "slide1Forecast",objContentShapes))[0]
objContentSlideForecast.text = CNSDETAILSLIDEFORECASTPREFIX + strRandomNumber0

# Populate assumptions placeholder (text)
objContentSlideAssumptions = list(filter(lambda x: x.name == "slide1Assumptions",objContentShapes))[0]
objContentSlideAssumptions.text = CNSDETAILSLIDEASSUMPTIONSPREFIX + CNSDETAILSLIDEASSUMPTIONSSTAGE + CNSDETAILSLIDEASSUMPTIONSSUFFIX + strRandomNumber1

# Populate screenshot
objContentSlideScreenshot = list(filter(lambda x: x.name == "slide1Screenshot",objContentShapes))[0]
plcName = objContentSlideScreenshot.name # Returns "slide1Screenshot"
plcType = objContentSlideScreenshot.placeholder_format.type # Returns 18
objContentSlideScreenshot.insert_picture("testShot.png",0,0)

I don't usually work in Python (but am completely enjoying) so please let me know if there is a glaring convention problem that I am unaware of.

Upvotes: 1

Views: 1218

Answers (1)

David Zemens
David Zemens

Reputation: 53663

The docs for this library suggest referencing the placeholder by it's idx.

The most reliable way to access a known placeholder is by its idx value

So I'd consider implementing that approach. But also and perhaps more importantly, here, you're working with the SlideLayout, not a slide instance! The layout contains shapes and placeholders, but they're not the same as the shapes and placeholders on the slide instance. (PPT's object model will find new ways to confound you, daily.)

objContentSlide = objPrs.slide_layouts[1]
objPrs.slides.add_slide(objContentSlide)

#collect the placeholders
objContentShapes = objContentSlide.placeholders

In the rest of your code, objContentSlide refers to the SlideLayout, not the Slide instance, and explains why you seem to be handling a LayoutPlaceholder rather than a Placeholder.

Instead, I would do something like the following (untested):

layout = objPrs.slide_layouts[1]  # handle the desired layout
slide = objPrs.slides.add_slide(layout) # create a slide instance from the layout
slide_shapes = slide.shapes
placeholders = slide.placeholders # handles the placeholders on our new slide instance

...

screenshot = list(filter(lambda x: x.name == "slide1Screenshot", slide_shapes))[0]
idx = screenshot.placeholder_format.idx
screenshot = placeholders[idx]
screenshot.insert_picture("testShot.png",0,0)

Upvotes: 2

Related Questions