python-pptx插入两张不同PNG图片重复显示同一张如何解决
问题原因
几个核心逻辑错误,和python-pptx库、图片文件本身无关:
- 坐标计算的运算优先级写反了。
Inches()的作用是将英寸单位的数值转换为python-pptx内部使用的EMU单位,你现在的写法是先把差值传入Inches()转成EMU,再做除法,算出来的坐标和预期差了数倍,甚至会出现负数坐标,要么把第二张图放到幻灯片可视区域外,要么让两张图完全重叠,视觉上就会觉得两次插入的是同一张图。
比如你写的Inches(16 - img[0]) / 5.5,实际是先算(16-图宽)对应的EMU值再除以5.5,和你想要的「(16-图宽)/5.5 英寸边距」结果完全不对。 - matplotlib保存图片后未关闭画布,PIL读取图片也未关闭文件句柄,会残留缓存和文件锁,容易触发图片读取异常。
- 额外隐藏问题:你自定义的
slide_size变量根本没有实际设置给PPT文件,python-pptx新建的演示文稿默认是4:3尺寸(宽10英寸,高7.5英寸),你按16:9的尺寸算坐标,本身就会出现坐标越界。
修复代码
- 修复尺寸转换工具函数,加dpi兜底,自动关闭图片文件句柄
- 保存matplotlib生成的图片后立刻关闭画布,清空缓存
- 所有坐标计算逻辑全部放到
Inches()括号内,保证传入的是最终的英寸数值 - 手动设置PPT为16:9尺寸,和你的计算基准对齐
from pptx import Presentation from pptx.util import Inches import matplotlib.pyplot as plt import pandas as pd from PIL import Image # 清理掉重复导入、未使用的模块即可 def px_to_inches(path, default_dpi=96): with Image.open(path) as im: # 部分PNG文件不存储dpi元数据,用默认屏幕dpi兜底避免报错 dpi = im.info.get('dpi', (default_dpi, default_dpi)) width = im.width / dpi[0] height = im.height / dpi[1] return (width, height) def sick_percentage(): bi_sql = SQLConnector(db='bi') sql_query = "<some query>" data_from_bi = bi_sql.query_by_str(sql_query) return data_from_bi df = sick_percentage() prs = Presentation() # 设置PPT为16:9尺寸,和你的计算基准对齐 prs.slide_width = Inches(16) prs.slide_height = Inches(9) slide = prs.slides.add_slide(prs.slide_layouts[5]) title = slide.shapes.title title.text = "<title>" fig, ax1 = plt.subplots() ax2 = ax1.twinx() df.plot(x='date', y='positives', kind='bar', color='orange', ax=ax1) df['percent_positive'].plot(x='date', kind='line', marker='d', ax=ax2) ax1.yaxis.tick_right() ax2.yaxis.tick_left() plt.savefig('graph.png', dpi=150, bbox_inches='tight') plt.close() # 必须加,清空matplotlib画布缓存 img = px_to_inches('graph.png') left = Inches((16 - img[0]) / 5.5) top = Inches((9 - img[1]) / 2) slide.shapes.add_picture('graph.png', left, top) img = px_to_inches('pkar.png') left = Inches((4 - img[0]) / 10) top = Inches((5 - img[1]) / 2) slide.shapes.add_picture('pkar.png', left, top) prs.save('chart-01.pptx')
改完运行后两张图会按预期位置显示,不会再出现重复同一张图的问题。如果第二张图位置不符合预期,直接打印left、top的数值,确认在幻灯片宽高范围内即可。
内容的提问来源于stack exchange,提问作者Ofir Tamir
相关产品推荐
相关产品推荐

