如何从内存向FastAPI端点返回动态GIF?
如何用FastAPI返回带动效的GIF文件?
我尝试从内存向FastAPI端点发送GIF,能成功传输但GIF没有动效;如果把GIF保存到本地,动效是正常的。希望不保存图片,仅在内存中处理后返回给端点,试过相关帖子的方法但没解决问题。
我尝试的代码
main.py
@app.get('/youtube/{video_id}.gif') def youtube_thumbnail (video_id: str, width: int = 320, height: int = 180): image = util.create_youtube_gif_thumbnail(video_id) return util.gif_to_streaming_response(image)
util.py
def gif_to_streaming_response(image: Image): imgio = BytesIO() image.save(imgio, 'GIF') imgio.seek(0) return StreamingResponse(content=imgio, media_type="image/gif") def create_gif(images, duration): gif = images[0] output = BytesIO() # 用这个时显示静态图,但保存到本地文件就有动效 # output = "./file.gif" 这个是正常的 gif.save(output, format='GIF', save_all=True, append_images=images, loop=0, duration=duration) return gif def create_youtube_gif_thumbnail(video_id: str): images = [read_img_from_url(f"https://i.ytimg.com/vi/{video_id}/{i}.jpg") for i in range(1,3)] return create_gif(images, 150)
问题原因
代码逻辑存在两个核心问题:
create_gif里虽然用save_all=True生成了动画GIF,但最后返回的是单张images[0]的Image对象,并没有把生成的动画内容传递出去gif_to_streaming_response接收单张Image后,又单独保存成了静态GIF,自然没有动效
修复方案
修改代码逻辑,直接在内存中生成完整的动画GIF字节流,然后返回给FastAPI响应:
修改后的util.py
from io import BytesIO from fastapi import StreamingResponse from PIL import Image def gif_to_streaming_response(gif_bytes: BytesIO): return StreamingResponse(content=gif_bytes, media_type="image/gif") def create_gif(images, duration): output = BytesIO() # 基于第一张图保存所有帧,注意append_images从第二张开始避免重复 images[0].save( output, format='GIF', save_all=True, append_images=images[1:], loop=0, duration=duration, disposal=2 # 关键参数:确保每一帧替换上一帧,避免帧残留 ) output.seek(0) return output def create_youtube_gif_thumbnail(video_id: str): images = [read_img_from_url(f"https://i.ytimg.com/vi/{video_id}/{i}.jpg") for i in range(1,3)] return create_gif(images, 150)
修改后的main.py
@app.get('/youtube/{video_id}.gif') def youtube_thumbnail(video_id: str, width: int = 320, height: int = 180): gif_bytes = util.create_youtube_gif_thumbnail(video_id) return util.gif_to_streaming_response(gif_bytes)
关键说明
create_gif现在直接返回包含完整动画的BytesIO对象,不再返回单张图片append_images=images[1:]避免重复添加第一张图,减少冗余disposal=2是PIL生成动画GIF的必要参数,它告诉GIF播放器在显示下一帧前清除当前帧,否则会出现帧叠加导致动效异常- 响应直接使用生成好的动画字节流,不需要二次保存,保证动效完整
内容的提问来源于stack exchange,提问作者Snailedlt
相关产品推荐
相关产品推荐

