You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python内存流存图用于PPTX时遇AttributeError问题求助

AttributeError when adding Matplotlib plot to PPTX via PIL Image

这个错误我之前也踩过坑!问题根源很明确:slide.shapes.add_picture() 方法只接受两种类型的输入:

  • 本地图片文件的路径字符串
  • 类文件对象(也就是有read()方法的对象,比如io.BytesIO

而你传入的是PIL的PngImageFile实例,它没有read()方法,自然会抛出AttributeError

最简单的解决方案:直接用BytesIO流传递

其实你完全不需要经过PIL这一步——matplotlib的savefig()已经把图片写入了BytesIO流,这个流本身就符合add_picture()的要求,直接传进去就行:

import io
from pptx import Presentation
from pptx.util import Inches
import matplotlib.pyplot as plt
import pandas as pd

# 1. 初始化PPT并添加幻灯片
prs = Presentation('Template.pptx')
title_slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(title_slide_layout)
title = slide.shapes.title
title.text = 'FileName'
left = top = Inches(1)

# 2. 绘制Matplotlib图表
fig, ax = plt.subplots()
df.groupby('Name').plot(x='Time', y='Score', ax=ax)
plt.tight_layout()  # 可选,防止图表元素被截断

# 3. 将图表保存到内存流(跳过PIL)
buf = io.BytesIO()
fig.savefig(buf, format='png', dpi=120)  # dpi可以调整图片清晰度
buf.seek(0)  # 必须把流指针移回开头,否则pptx读不到内容

# 4. 直接把流传给add_picture
pic = slide.shapes.add_picture(buf, left, top)

# 最后别忘保存PPT
prs.save('Result.pptx')

如果需要用PIL处理图片(比如调整尺寸)

要是你确实需要对图片做裁剪、缩放等操作,那处理完后得把PIL对象重新写入一个新的BytesIO流,再传给add_picture()

import io
from PIL import Image
from pptx import Presentation
from pptx.util import Inches
import matplotlib.pyplot as plt
import pandas as pd

# 1. 初始化PPT部分和之前一样
prs = Presentation('Template.pptx')
title_slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(title_slide_layout)
title = slide.shapes.title
title.text = 'FileName'
left = top = Inches(1)

# 2. 绘制图表
fig, ax = plt.subplots()
df.groupby('Name').plot(x='Time', y='Score', ax=ax)
plt.tight_layout()

# 3. 保存到流 -> 用PIL处理 -> 写入新流
buf = io.BytesIO()
fig.savefig(buf, format='png')
buf.seek(0)
im = Image.open(buf)

# 示例:调整图片尺寸
im = im.resize((900, 600))

# 把处理后的图片写入新的BytesIO
processed_buf = io.BytesIO()
im.save(processed_buf, format='png')
processed_buf.seek(0)

# 4. 添加处理后的图片到PPT
pic = slide.shapes.add_picture(processed_buf, left, top)

prs.save('Processed_Result.pptx')

额外注意点

  • 每次操作BytesIO后一定要调用seek(0),不然读取流的时候会从末尾开始,导致读不到任何内容。
  • 记得导入所有需要的库(比如你原来的代码里没导入matplotlib.pyplot,运行会报错)。
  • 可以通过savefig()dpi参数调整图片清晰度,数值越高图片越清晰,但PPT文件也会越大。

内容的提问来源于stack exchange,提问作者FunkyMore

火山引擎 最新活动