PIL - 将 GIF 帧转换为 JPG
Posted
技术标签:
【中文标题】PIL - 将 GIF 帧转换为 JPG【英文标题】:PIL - Convert GIF Frames to JPG 【发布时间】:2012-05-03 09:20:13 【问题描述】:我尝试使用 Python 图像库将 gif 转换为单个图像, 但它会导致奇怪的帧
输入的 gif 是:
Source Image http://longcat.de/gif_example.gif
在我的第一次尝试中,我尝试将带有 Image.new 的图像转换为 RGB 图像,以 255,255,255 作为白色背景 - 与任何其他图像一样 我在互联网上找到的示例:
def processImage( infile ):
try:
im = Image.open( infile )
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
try:
while 1:
background = Image.new("RGB", im.size, (255, 255, 255))
background.paste(im)
background.save('foo'+str(i)+'.jpg', 'JPEG', quality=80)
i += 1
im.seek( im.tell() + 1 )
except EOFError:
pass # end of sequence
但它会导致奇怪的输出文件:
Example #1 http://longcat.de/gif_example1.jpg
我的第二次尝试是,先将 gif 转换为 RGBA,然后使用 它的透明蒙版,使透明部分变白:
def processImage( infile ):
try:
im = Image.open( infile )
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
try:
while 1:
im2 = im.convert('RGBA')
im2.load()
background = Image.new("RGB", im2.size, (255, 255, 255))
background.paste(im2, mask = im2.split()[3] )
background.save('foo'+str(i)+'.jpg', 'JPEG', quality=80)
i += 1
im.seek( im.tell() + 1 )
except EOFError:
pass # end of sequence
导致如下输出:
Example #2 http://longcat.de/gif_example2.jpg
与第一次尝试相比的优势在于,第一帧看起来不错 但正如你所看到的,其余的都坏了
接下来我应该尝试什么?
编辑:
我认为我离解决方案更近了
Example #3 http://longcat.de/gif_example3.png
我不得不将第一张图片的调色板用于其他图片, 并将其与前一帧合并(对于使用 差异图像)
def processImage( infile ):
try:
im = Image.open( infile )
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
size = im.size
lastframe = im.convert('RGBA')
mypalette = im.getpalette()
try:
while 1:
im2 = im.copy()
im2.putpalette( mypalette )
background = Image.new("RGB", size, (255,255,255))
background.paste( lastframe )
background.paste( im2 )
background.save('foo'+str(i)+'.png', 'PNG', quality=80)
lastframe = background
i += 1
im.seek( im.tell() + 1 )
except EOFError:
pass # end of sequence
但我其实不知道,为什么我的透明度是黑色的,而不是白色的 即使我修改调色板(将透明度通道更改为白色) 或者使用透明蒙版,背景还是黑色的
【问题讨论】:
【参考方案1】:首先,JPEG
不支持透明度!但这不是唯一的问题。当您移动到GIF
的下一帧时,palette
信息丢失(problem witn PIL?) - 所以PIL
无法正确转换为RGBA
框架(因此第一帧还可以,但其他所有帧都很糟糕)。所以解决方法是为每一帧添加palette
,(这是你在上一个代码示例中所做的,但你的问题是你保存为RGB
而不是RGBA
所以你有没有阿尔法/透明度通道。而且你做了一些不必要的事情..)。无论如何,这里是透明的.png和更正的代码,希望它有一些用处:)
import Image
import sys
def processImage(infile):
try:
im = Image.open(infile)
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
mypalette = im.getpalette()
try:
while 1:
im.putpalette(mypalette)
new_im = Image.new("RGBA", im.size)
new_im.paste(im)
new_im.save('foo'+str(i)+'.png')
i += 1
im.seek(im.tell() + 1)
except EOFError:
pass # end of sequence
processImage('gif_example.gif')
【讨论】:
非常感谢!我在最后一帧使用粘贴,因为有些 gif 对每一帧都使用了差异! 嗯,当框架有不同的调色板时,像这样替换调色板会得到不正确的结果。其中一个例子是图像imagemagick.org/Usage/anim_opt/bunny_bgnd.gif(我想,不确定我是否在复制和粘贴正确的链接)。我看到的另一个问题可能与 PIL 版本之间的差异有关,但我没有得到与你相同的结果(除了第一个,我在所有帧中都得到灰色区域,它应该是透明的)。对于像 imagemagick.org/Usage/anim_opt/bunny_bgnd_opttrans.gif 这样的 gif,也会发生同样的情况。 @mmgp - 嗯,是的,我可以看到具有不同调色板的框架可能会造成问题。我同意你得到不同的结果可能是版本问题。不幸的是,我现在没有时间看这个,如果你有修复,请编辑我的答案,或者添加你自己的。不错。 @fraxel PIL 并不容易。我找到了这个答案,因为一个新的问题与之相关,我在***.com/a/14550885/1832154 尝试了一些东西,但是对于另一种类型的 GIF 动画(不是我在之前评论中喜欢的那些),这仍然失败。【参考方案2】:在图像查看器上查看图像时,即使透明度设置为零,它也倾向于将图像显示为黑色。确保您的图像真正透明的一种方法是将其合并到另一个上。应该看到“表情符号”,同时不妨碍其他图像。尝试:
background = Image.open('someimage.jpg') #an existing image
foreground = Image.open('foo.jpg') #one of the above images
background.paste(foreground, (0,0), foreground)
background.save('trial.jpg') #the composite image
理论上,如果您在图像查看器中打开“trial.jpg”并保留初始图像的内容,并且在其顶部是 foo 图像,那么您将确定它是否只是图像查看器和您的图片很好……
【讨论】:
.jpeg 不支持透明度 :(【参考方案3】:source here
Image.open('image.gif').convert('RGB').save('image.jpg')
【讨论】:
OP 询问是否将动画(多帧)gif 转换为一系列 jpeg;这只会保存第一帧【参考方案4】:这对我有用。下面的例子展示了将 image.gif 转换为 8 个白色背景的 jpg 格式图像。
from PIL import Image
from PIL import GifImagePlugin
def gif2jpg(file_name: str, num_key_frames: int, trans_color: tuple):
"""
convert gif to `num_key_frames` images with jpg format
:param file_name: gif file name
:param num_key_frames: result images number
:param trans_color: set converted transparent color in jpg image
:return:
"""
with Image.open(file_name) as im:
for i in range(num_key_frames):
im.seek(im.n_frames // num_key_frames * i)
image = im.convert("RGBA")
datas = image.getdata()
newData = []
for item in datas:
if item[3] == 0: # if transparent
newData.append(trans_color) # set transparent color in jpg
else:
newData.append(tuple(item[:3]))
image = Image.new("RGB", im.size)
image.getdata()
image.putdata(newData)
image.save('.jpg'.format(i))
gif2jpg("image.gif", 8, (255, 255, 255)) # convert image.gif to 8 jpg images with white background
【讨论】:
以上是关于PIL - 将 GIF 帧转换为 JPG的主要内容,如果未能解决你的问题,请参考以下文章
CodeIgniter - 将 GIF 转换为 JPG?可能的?