Flask中如何在<img>标签显示从S3读取的PIL图片?
解决Flask前端无法显示S3获取图片的问题
问题原因
你直接把PIL的PngImageFile对象传给了模板,浏览器的<img>标签的src属性需要的是图片的URL或者Base64编码的图片数据,而不是Python对象,所以才会显示对象的字符串表示。
解决方案
有两种常用方法可以解决这个问题:
方法1:将图片转换为Base64编码字符串
修改read_froms3img函数,返回Base64编码的图片数据,而不是PIL对象:
import base64 import io import boto3 from PIL import Image def read_froms3img(image_name): ep_url=URL access_id=ID_KEY access_key=SECRET_KEY s3_resource = boto3.resource(service_name = "s3",endpoint_url=ep_url, aws_access_key_id=access_id, aws_secret_access_key=access_key) bucket = s3_resource.Bucket(s3_bucket) image = bucket.Object('Images/plot.png') img_data = image.get().get('Body').read() # 将图片转换为Base64编码 img_base64 = base64.b64encode(img_data).decode('utf-8') # 返回带MIME类型的Base64字符串,供img标签使用 return f"data:image/png;base64,{img_base64}"
视图函数调用:
contents = read_froms3img("plot.png") return render_template('data.html', form_data = form_data, html_code = html, filename = contents)
HTML部分保持原代码即可:
<img src="{{filename}}" height="50%" width="65%">
方法2:生成S3图片的预签名URL
如果图片文件较大,Base64会增加数据体积,推荐使用S3的预签名URL,这个URL是临时可访问的,无需将图片数据传到服务器:
import boto3 def get_s3_presigned_url(image_name): ep_url=URL access_id=ID_KEY access_key=SECRET_KEY s3_client = boto3.client(service_name = "s3",endpoint_url=ep_url, aws_access_key_id=access_id, aws_secret_access_key=access_key) # 生成预签名URL,有效期设置为3600秒(1小时),可按需调整 presigned_url = s3_client.generate_presigned_url('get_object', Params={'Bucket': s3_bucket, 'Key': 'Images/plot.png'}, ExpiresIn=3600) return presigned_url
视图函数调用:
contents = get_s3_presigned_url("plot.png") return render_template('data.html', form_data = form_data, html_code = html, filename = contents)
HTML部分同样无需修改,直接使用{{filename}}作为src的值即可。
注意事项
- 方法1适合小尺寸图片,Base64会使图片体积增加约30%;
- 方法2适合大图片,预签名URL的有效期可根据需求调整,避免长期暴露;
- 确保S3存储桶的权限配置正确,你的AWS密钥需要具备对应的
get_object权限。
内容的提问来源于stack exchange,提问作者SM079
相关产品推荐
相关产品推荐

