You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask中嵌入MongoDB图片到PDF遇报错,求解决方案

问题解决与优化方案

一、报错原因及修复

报错AttributeError: 'ImageReader' object has no attribute 'read'是因为你错误地对ImageReader实例调用了read()方法——ImageReader本身并不提供read()接口,它是用于读取图片内容的对象,而非字节流容器。

修复当前报错的代码片段

替换原代码中从remote_file = ImageReader(urlopen(img_url)).read()到return send_file(...)的部分:

from PIL import Image
import io

# 获取图片字节流
img_bytes = urlopen(img_url).read()
memory_file = io.BytesIO(img_bytes)

# 重新初始化画布并绘制内容
buf = io.BytesIO()
c = canvas.Canvas(buf, pagesize=letter)
c.setFont("Helvetica", 20)
c.drawString(100, 720, dog_name)
# 直接在画布上绘制图片,可调整位置和尺寸
c.drawImage(memory_file, 100, 500, width=200, height=200)
c.save()  # 必须调用save完成画布内容写入
buf.seek(0)

return send_file(buf, mimetype='application/pdf')

二、更优的PDF图片嵌入方案

你的现有代码存在冗余步骤(创建两个PDF再合并),更高效的方式是直接在ReportLab Canvas上绘制所有元素(文字+图片),避免不必要的PDF合并操作,同时提升代码可读性和性能。

完整优化后的代码

from flask import send_file
import pymongo
from bson import json_util
import io
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from PIL import Image
from urllib.request import urlopen

def get(self, usermail, dog_name):
    # 连接MongoDB并查询数据
    client = pymongo.MongoClient('mongodb://uri')
    filter_query = {'UserMail': usermail, 'title': dog_name}
    # 直接提取单条结果(假设查询唯一匹配)
    dog_data = list(client['db']['Todo'].find(filter=filter_query))[0]
    
    # 提取宠物信息
    img_url = 'https://url' + dog_data['DogImg']
    dog_age = dog_data['Age']
    dog_desc = dog_data['DogDescription']
    dog_name = dog_data['title']
    dog_breed = dog_data['Breed']

    # 创建PDF画布
    buf = io.BytesIO()
    c = canvas.Canvas(buf, pagesize=letter)
    page_width, page_height = letter

    # 绘制居中标题
    c.setFont("Helvetica-Bold", 20)
    title_x = page_width/2 - len(dog_name)*6  # 粗略计算居中位置
    c.drawString(title_x, page_height - 50, dog_name)

    # 绘制自适应尺寸的图片
    try:
        img_bytes = urlopen(img_url).read()
        img_stream = io.BytesIO(img_bytes)
        img = Image.open(img_stream)
        # 计算缩放比例,避免图片超出页面
        max_width = page_width - 100
        max_height = page_height - 200
        scale = min(max_width / img.width, max_height / img.height)
        draw_width, draw_height = img.width*scale, img.height*scale
        # 居中绘制图片
        c.drawImage(img_stream, (page_width-draw_width)/2, page_height - 150 - draw_height,
                    width=draw_width, height=draw_height)
    except Exception:
        # 图片加载失败时绘制提示
        c.setFont("Helvetica", 12)
        c.drawString(page_width/2 - 50, page_height - 200, "图片加载失败")

    # 绘制宠物详情信息
    c.setFont("Helvetica", 14)
    info_y = page_height - 200 - draw_height - 30
    c.drawString(50, info_y, f"品种: {dog_breed}")
    c.drawString(50, info_y - 30, f"年龄: {dog_age}")
    c.drawString(50, info_y - 60, f"描述: {dog_desc}")

    # 保存画布并返回PDF
    c.save()
    buf.seek(0)
    return send_file(buf, mimetype='application/pdf', download_name=f"{dog_name}_信息.pdf")

优化点说明

  • 简化数据处理:省去JSON序列化/反序列化、DataFrame转换的冗余步骤,直接从MongoDB结果中提取数据,提升性能。
  • 直接绘制元素:在同一个画布上完成文字和图片绘制,避免多PDF合并的额外开销。
  • 自适应布局:自动计算图片缩放比例,确保内容适配页面,同时保持居中显示。
  • 错误处理:添加图片加载失败的异常捕获,提升代码健壮性。
  • 用户体验优化:设置自定义下载文件名,方便用户识别文件。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 06:55:23