【问题标题】:PIL - Convert GIF Frames to JPGPIL - 将 GIF 帧转换为 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

但我其实不知道,为什么我的透明度是黑色的,而不是白色的 即使我修改调色板(将透明度通道更改为白色) 或者使用透明蒙版,背景还是黑色的

【问题讨论】:

    标签: python image-processing python-imaging-library gif jpeg


    【解决方案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 并不容易。我找到了这个答案,因为一个新的问题与之相关,我在stackoverflow.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
    
    

    【讨论】:

      猜你喜欢
      • 2012-01-25
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      • 2021-02-01
      • 2011-06-21
      • 1970-01-01
      • 2021-10-07
      • 2012-01-22
      相关资源
      最近更新 更多