python-pptx add_picture替换图片时descr被改为image.png问题求解
问题描述
- 使用场景:通过python-pptx生成演示文稿后,会手动添加部分幻灯片,后续需要修改一张或多张图片时,希望重新运行程序可按相同文件名替换对应图片。
- 故障现象:首次运行替换功能通常正常,替换后可保留原图片的
descr属性,但多数情况下替换后图片descr会被自动设置为image.png,导致后续替换时无法定位目标图片。
最初编写的删图重插版替换函数:
def replace(self, newPic): for slide in self.pres.slides: for shape in slide.shapes: try: if shape._pic.nvPicPr.cNvPr.get('descr') == newPic: top, left, width, height = shape.top, shape.left, shape.width, shape.height self.deleteShape(shape) img = slide.shapes.add_picture(self.inDir + "/" + newPic, left, top, width, height) imgDescr = img._pic.nvPicPr.cNvPr.get('descr') except AttributeError: pass
后续尝试的直接替换图片二进制方案运行时报错:
def replace(self, newPic): #If in list with every figure for slide in self.pres.slides: for shape in slide.shapes: try: if shape._pic.nvPicPr.cNvPr.get('descr') == newPic: imgPic = shape._pic imgRID = imgPic.xpath('./p:blipFill/a:blip/@r:embed')[0] imgPart = shape.part.relatedpart(imgRID) with open(self.inDir + "/" + newPic, 'rb') as f: rImgBlob = f.read() # replace imgPart._blob = rImgBlob except AttributeError: pass
报错信息:
imgPart = shape.part.relatedpart(imgRID) AttributeError: 'SlidePart' object has no attribute 'relatedpart'
解决方案
1. 二进制替换方案报错修复(优先推荐)
报错根因是方法名拼写错误:python-pptx中获取关联部件的方法是下划线分隔的related_part(),不是全小写连写的relatedpart。
该方案不需要删除原有形状重新插入,可完整保留原图片的位置、尺寸、裁剪效果、动画、层级、样式等所有属性,也不会自动修改descr属性,稳定性远高于删图重插方案。
修正后的代码:
def replace(self, newPic): for slide in self.pres.slides: for shape in slide.shapes: try: if shape._pic.nvPicPr.cNvPr.get('descr') == newPic: imgPic = shape._pic imgRID = imgPic.xpath('./p:blipFill/a:blip/@r:embed')[0] # 修正方法名拼写 imgPart = shape.part.related_part(imgRID) with open(f"{self.inDir}/{newPic}", 'rb') as f: rImgBlob = f.read() # 替换二进制内容 imgPart._blob = rImgBlob except AttributeError: pass
注意事项:
- 如果新图片和原图片格式不一致(比如原PNG替换为JPG),需要同步修改图片部件的Content-Type,否则PPT打开会报错,可在替换blob后添加对应逻辑:
# 例:替换为jpg格式时设置 imgPart.content_type = "image/jpeg" # 替换为png格式时设置 # imgPart.content_type = "image/png"
2. 删图重插方案修复
如果坚持使用删图重插逻辑,故障原因是插入新图片后没有手动设置descr属性,python-pptx会自动给新插入的图片descr赋值为默认文件名,很容易出现匹配值丢失的问题。需要在add_picture后手动给descr赋值为目标匹配值:
def replace(self, newPic): for slide in self.pres.slides: for shape in slide.shapes: try: if shape._pic.nvPicPr.cNvPr.get('descr') == newPic: top, left, width, height = shape.top, shape.left, shape.width, shape.height self.deleteShape(shape) img = slide.shapes.add_picture(f"{self.inDir}/{newPic}", left, top, width, height) # 手动设置descr属性,不要依赖默认值 img._pic.nvPicPr.cNvPr.set('descr', newPic) except AttributeError: pass
内容的提问来源于stack exchange,提问作者Selfors
相关产品推荐
相关产品推荐

