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

如何用Pillow保存图像数组为GIF?解决黑白负色异常

问题描述

尝试修改GIF文件,步骤为:读取GIF,将单帧解析为数组,为数组添加若干最后一帧的副本,再重新保存为GIF。功能可实现,但保存后的GIF呈现黑白负色效果。

代码示例

from PIL import Image
from PIL import GifImagePlugin
from PIL import ImageSequence 
import imageio

imageObject = Image.open(directory+gif_path)
frames = [frame.copy() for frame in ImageSequence.Iterator(imageObject)]
ending_frame = frames[-1].copy()
for val in range(5):
    frames.append(ending_frame)

imageio.mimsave('new.gif',frames)

帧信息

帧数组frames的元素均为**P模式(调色板模式)**的PIL图像:

[<PIL.Image.Image image mode=P size=720x360 at 0x2661F2F50A0>,
 <PIL.Image.Image image mode=P size=720x360 at 0x2661F4A7BE0>,
 <PIL.Image.Image image mode=P size=720x360 at 0x2661F4B3250>,
 <PIL.Image.Image image mode=P size=720x360 at 0x2661F4B3820>,
 <PIL.Image.Image image mode=P size=720x360 at 0x2661F4B38E0>,
 <PIL.Image.Image image mode=P size=720x360 at 0x2661F4B3970>]

怀疑问题出在Pillow和imageio的色彩处理逻辑差异,想了解原因及如何用Pillow直接保存PIL图像数组为GIF。


问题原因

确实是Pillow和imageio的色彩模式兼容问题:
P模式的图像是用索引值对应调色板里的RGB颜色,而imageio在处理PIL的P模式图像时,会错误地把索引值直接当成RGB灰度值解析,导致颜色映射完全错乱,出现黑白负色的效果。


解决方法

方案1:修复imageio保存逻辑

把P模式图像转成RGB模式再保存,让imageio能正确识别色彩:

from PIL import Image
from PIL import ImageSequence 
import imageio

imageObject = Image.open(directory+gif_path)
# 转换为RGB模式
frames = [frame.copy().convert("RGB") for frame in ImageSequence.Iterator(imageObject)]
ending_frame = frames[-1].copy()
for val in range(5):
    frames.append(ending_frame)

# 保留原GIF的帧间隔
imageio.mimsave('new.gif', frames, duration=imageObject.info['duration'])

方案2:直接用Pillow保存GIF(推荐)

不需要依赖imageio,用Pillow原生方法保存,完美保留原调色板和播放参数:

from PIL import Image
from PIL import ImageSequence 

imageObject = Image.open(directory+gif_path)
frames = [frame.copy() for frame in ImageSequence.Iterator(imageObject)]
ending_frame = frames[-1].copy()
for val in range(5):
    frames.append(ending_frame)

# 通过第一帧的save方法保存整个序列
frames[0].save(
    'new.gif',
    save_all=True,
    append_images=frames[1:],
    duration=imageObject.info['duration'],  # 原帧间隔
    loop=imageObject.info.get('loop', 0),  # 0=无限循环,保留原设置
    disposal=imageObject.info.get('disposal')  # 保留原帧处理方式,避免闪烁
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 06:54:47