PIL - конвертировать GIF-фреймы в JPG

Я попытался преобразовать gif в отдельные изображения с помощью библиотеки изображений Python, но это приводит к странным кадрам

Ввод gif:

Исходный образ 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

но это приводит к появлению странных выходных файлов:

Пример # 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

в результате чего получается такой вывод:

Пример # 2 http://longcat.de/gif_example2.jpg

Преимущество перед первой попыткой состояло в том, что первый кадр выглядит довольно неплохо Но, как вы можете видеть, остальное сломано

Что мне делать дальше?

Edit:

Думаю, я намного ближе к решению

Пример # 3 http://longcat.de/gif_example3.png

Мне пришлось использовать палитру первого изображения для других изображений, и объединить его с предыдущим фреймом (для анимаций gif, которые используют Diff-изображения)

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 теряется ( проблема witn PIL?) - так что PIL не может правильно преобразовать в рамки RGBA (Следовательно, первый кадр окуривает, но все остальные являются отвратительными). Итак, обход - добавить palette назад для каждого фрейма (это то, что вы делали в своем последнем примере кода, но ваша проблема заключалась в том, что вы сохраняли как RGB not RGBA, чтобы вы нет канала альфа/прозрачности. Также вы делали несколько ненужных вещей..). Во всяком случае, вот .png с прозрачностью и исправленным кодом, надеюсь, что это будет полезно:)

enter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description here

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')

Ответ 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, то вы точно знаете, будет ли это только просмотрщик изображений и ваш изображения в порядке...